Package: release.debian.org Severity: normal Tags: trixie X-Debbugs-Cc: wtmpdb@packages.debian.org, tg@debian.org Control: affects -1 + src:wtmpdb User: release.debian.org@packages.debian.org Usertags: pu +-------------------------+-------------------------------------------+ | Package | Reason | +-------------------------+-------------------------------------------+ | wtmpdb [1] | Move wtmp.db to /var/log; use logrotate | | | to rotate and prune boot & login records | +-------------------------+-------------------------------------------+ [ Reason ] wtmpdb is a new package in trixie. The log rotation capability shipped by upstream and initially packaged in Debian did not prune logs (#1094965) and had only the negative utility of atomising already compact[1] log files every month. It proved difficult to devise a scheme in which one could have confidence as being robust enough for trixie, therefore rotation was disabled entirely, as the least harmful of the known options. Since the trixie release, collaborators on the BTS have helped to design a solution in which we can have confidence, based around the trusted logrotate daemon and with a patch to upstream for handling empty files, which has now been accepted and released upstream. This version also moves the wtmp.db database into the proper log location (#1117719) and incidentally fixes an issue a user found with incorrect permissions under the previous (since disabled) log rotation scheme (#1076308). I propose to release a version into trixie that uses the new upstream with logrotate, having been encouraged by Thorsten Glasser <tg@debian.org> to do so. It would be a good idea to get these changes into a point release before the default log rotation is triggered on New Year's Day 2026, so that users see consistent behaviour over the lifetime of this OS version. [ Impact ] - #1093965 (important) Potentially unbounded log growth, violating 10.8. (But unlikely to be huge - grows much more slowly[1] than wtmp which was rarely rotated in bookworm due to default 'minsize 1M' config.) - #1117719 (important) Logs in a surprising location, volating 10.8 and 9.11 (FHS compliance) - see user complaint about the location of personally-identifying information in https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1094965#114 But this is arguable as to impact and compliance - databases like this, e.g. dhcpd leases, can be found in the state directory. - #1076308 (important) If a user enabled the original (since disabled by default) rotation scheme they would get new and rotated logs created with the wrong ownership and mode. This only affected users who changed the default umask or the database's mode or ownership. [ Tests ] Manual tests conducted: - Forced log rotation - Purge to remove logs - Install from nothing with old wtmp data to be converted - Upgrade from 0.73.0-3 with data in old location - Upgrade from 0.73.0-3 with data in new location but no symlink - Upgrade from 0.73.0-3 with data in both locations [ideal end state not achieved - as intended: avoid loss of data] - Upgrade with symlink already in place by prior manual intervention - Leftover conffile removed - Custom ownership and permissions retained on rotation - tmpfiles creation of missing link post-installation [ Risks ] The code change is small but there is the possibility of some unanticipated upgrade path not working optimally, particularly for users who installed versions from testing/unstable before the trixie release, but caveat emptor for non-stable users. The possible failure modes do not seem serious: there is no reason to expect that there would be loss of data. The use of a symlink in addition to patching the source code is to increase the resilience of the solution. [ Checklist ] [X] *all* changes are documented in the d/changelog [X] I reviewed all changes and I approve them [X] attach debdiff against the package in (old)stable [X] the issue is verified as fixed in unstable [ Changes ] > * New upstream version. > - handle reading and writing empty files benignly > - drop patch applied upstream. The upstream changelog is as follows: === begin upstream changes === > Version 0.75.0 > * Use empty memory table instead of failing to read empty file This change is necessary for the log rotation to work smoothly, because logrotate can create an empty file with the right permissions and it will be handled well by wtmpdb. Without this, an atomic copy of a skeleton database file with the correct permissions would have been fragile to achieve in scripts (the problems with this were discussed on #1094965). > * libwtmpdb: enhance/unify error messages Cosmetic change but helpful to users - an appropriate addition for trixie. > Version 0.74.0 > * Fix varlink interface name (rebootmgr vs wtmpdb) String change for component not built in Debian package. > * import: match login by tty if non-zero pid does not match This replaces a patch carried in the existing Debian package. === end upstream changes === I think it is clearer to take the upstream version with the two unnecessary changes than to carry the two patches in debian that it obviates. > * Move database to /var/log from /var/lib/wtmpdb, per policies 10.8 > and 9.11 (FHS). (Closes: #1117719) Patch the library to use /var/log as the default location for the wtmp.db database. This is done WITHOUT changing the header file so that libwtmp-dev can be used to build binaries faithfully for use outside Debian, to avoid concerns over ABI breakage. A symlink is installed from the old to new log locations by postinst maintscript (and defined in tmpfiles.d for extra resilience). > * Rotate database with logrotate. > - cause rotated logs to be pruned per policy 10.8. (Closes: #1094965) The upstream-supplied rotation scheme does not prune logs and requires fragile external scripting to make it do so. By switching to using logrotate we now achieve pruning. > - cause new and rotated files to keep permissions. (Closes: #1076308) This fix is a side-effect of the new rotation scheme. > * Remove database on purge per policy 10.8. This policy violation is fixed with a postrm maintscript. > * Remove leftover /etc/cron.monthly/wtmpdb conffile to avoid the > old and broken rotation scheme from 0.73.0-2 and earlier from > being invoked in addition to the new scheme. This is fixed with 'remove-on-upgrade' for any users who installed an earlier version of this package from testing/unstable. There is no corresponding issue with the dropped systemd time unit because that was not a conffile. > * Update README.Debian to reflect changes. [ Other info ] I request your approval to upload to stable-proposed-updatesm, please and recommend that this is also distributed in stable-updates due to the time-related impact. Thanks, Andrew [1] wtmpdb databases tend to grow at a tenth of the rate of wtmp logs, for example 80K vs 756K for one converted set of logs.
diff -Nru wtmpdb-0.73.0/debian/changelog wtmpdb-0.75.0/debian/changelog --- wtmpdb-0.73.0/debian/changelog 2025-05-04 18:39:33.000000000 +0100 +++ wtmpdb-0.75.0/debian/changelog 2025-10-11 23:26:22.000000000 +0100 @@ -1,3 +1,21 @@ +wtmpdb (0.75.0-0+deb13u1) trixie; urgency=medium + + * New upstream version. + - handle reading and writing empty files benignly + - drop patch applied upstream. + * Move database to /var/log from /var/lib/wtmpdb, per policies 10.8 + and 9.11 (FHS). (Closes: #1117719) + * Rotate database with logrotate. + - cause rotated logs to be pruned per policy 10.8. (Closes: #1094965) + - cause new and rotated files to keep permissions. (Closes: #1076308) + * Remove database on purge per policy 10.8. + * Remove leftover /etc/cron.monthly/wtmpdb conffile to avoid the + old and broken rotation scheme from 0.73.0-2 and earlier from + being invoked in addition to the new scheme. + * Update README.Debian to reflect changes. + + -- Andrew Bower <andrew@bower.uk> Sat, 11 Oct 2025 23:26:22 +0100 + wtmpdb (0.73.0-3) unstable; urgency=medium * Do not rotate database by default because the rotation operation does diff -Nru wtmpdb-0.73.0/debian/control wtmpdb-0.75.0/debian/control --- wtmpdb-0.73.0/debian/control 2025-05-04 18:39:33.000000000 +0100 +++ wtmpdb-0.75.0/debian/control 2025-10-11 23:26:05.000000000 +0100 @@ -32,6 +32,7 @@ util-linux (<< 2.40.1-3), Recommends: libpam-wtmpdb, + logrotate, Multi-Arch: foreign Description: utility to display login/logout/reboot information This package provides the program wtmpdb, which reads wtmpdb's diff -Nru wtmpdb-0.73.0/debian/libwtmpdb0.postinst wtmpdb-0.75.0/debian/libwtmpdb0.postinst --- wtmpdb-0.73.0/debian/libwtmpdb0.postinst 1970-01-01 01:00:00.000000000 +0100 +++ wtmpdb-0.75.0/debian/libwtmpdb0.postinst 2025-10-11 15:00:41.000000000 +0100 @@ -0,0 +1,29 @@ +#!/bin/sh + +set -e + +lib_log="${DPKG_ROOT:-}/var/lib/wtmpdb/wtmp.db" +new_log="${DPKG_ROOT:-}/var/log/wtmp.db" + +# Effect the conversion from storing the live log in the state directory to +# storing it in its proper place, the logs directory. Also set up the symlink +# where tmpfiles.d is not available. +if [ "$1" = "configure" ] +then + if [ -s "$lib_log" ] && [ ! -h "$lib_log" ] && [ ! -s "$new_log" ] + then + mv -f "$lib_log" "$new_log" + fi + + # The unhandled case is records in both locations. For this we need + # a 'wtmpdb merge' operation called in wtmpdb.postinst but no such + # operation yet exists. + + if [ ! -f "$lib_log" ] + then + mkdir -p "$(dirname "$lib_log")" + ln -sf ../../log/wtmp.db "$lib_log" + fi +fi + +#DEBHELPER# diff -Nru wtmpdb-0.73.0/debian/libwtmpdb0.postrm wtmpdb-0.75.0/debian/libwtmpdb0.postrm --- wtmpdb-0.73.0/debian/libwtmpdb0.postrm 1970-01-01 01:00:00.000000000 +0100 +++ wtmpdb-0.75.0/debian/libwtmpdb0.postrm 2025-10-11 23:26:05.000000000 +0100 @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +if [ "$1" = "purge" ] +then + rm -rf "${DPKG_ROOT:-}"/var/log/wtmp.db* "${DPKG_ROOT:-}"/var/lib/wtmpdb +fi + +#DEBHELPER# diff -Nru wtmpdb-0.73.0/debian/libwtmpdb0.wtmpdb.logrotate wtmpdb-0.75.0/debian/libwtmpdb0.wtmpdb.logrotate --- wtmpdb-0.73.0/debian/libwtmpdb0.wtmpdb.logrotate 1970-01-01 01:00:00.000000000 +0100 +++ wtmpdb-0.75.0/debian/libwtmpdb0.wtmpdb.logrotate 2025-10-11 15:00:41.000000000 +0100 @@ -0,0 +1,7 @@ +/var/log/wtmp.db { + missingok + yearly + create + nocompress + rotate 4 +} diff -Nru wtmpdb-0.73.0/debian/not-installed wtmpdb-0.75.0/debian/not-installed --- wtmpdb-0.73.0/debian/not-installed 2025-05-04 18:39:33.000000000 +0100 +++ wtmpdb-0.75.0/debian/not-installed 2025-10-11 15:00:41.000000000 +0100 @@ -1,3 +1,5 @@ +usr/lib/systemd/system/wtmpdb-rotate.service +usr/lib/systemd/system/wtmpdb-rotate.timer usr/lib/systemd/system/wtmpdbd.service usr/lib/systemd/system/wtmpdbd.socket usr/libexec/wtmpdbd diff -Nru wtmpdb-0.73.0/debian/patches/db-in-var-log.patch wtmpdb-0.75.0/debian/patches/db-in-var-log.patch --- wtmpdb-0.73.0/debian/patches/db-in-var-log.patch 1970-01-01 01:00:00.000000000 +0100 +++ wtmpdb-0.75.0/debian/patches/db-in-var-log.patch 2025-10-11 23:26:05.000000000 +0100 @@ -0,0 +1,207 @@ +From: Andrew Bower <andrew@bower.uk> +Date: Thu, 9 Oct 2025 22:02:22 +0100 +Subject: Use /var/log/wtmp.db as default database location + +Forwarded: not-needed +--- + README.md | 2 +- + lib/libwtmpdb.c | 3 +++ + man/pam_wtmpdb.8.xml | 15 ++++++++++++--- + man/wtmpdb.8.xml | 21 +++++++++++++++------ + src/pam_wtmpdb.c | 3 +++ + tmpfiles.d/wtmpdb.conf | 1 + + units/wtmpdb-rotate.service | 2 +- + units/wtmpdb-update-boot.service | 2 +- + 8 files changed, 37 insertions(+), 12 deletions(-) + +diff --git a/README.md b/README.md +index e2f8a0f..2e02328 100644 +--- a/README.md ++++ b/README.md +@@ -30,7 +30,7 @@ The package constists of a library, PAM module, a commandline interface and an o + * `wtmpdb` is used to add reboot and shutdown entries and to display existing entries (like `last`). + * `wtmpdbd` is used to manage the database in a secure way. + +-By default the database will be written as `/var/lib/wtmpdb/wtmp.db`. ++By default the database will be written as `/var/log/wtmp.db`, with a symbolic link from `/var/lib/wtmpdb/wtmp.db`. + + ## Configuration + +diff --git a/lib/libwtmpdb.c b/lib/libwtmpdb.c +index 8e5f2d9..a0c54e3 100644 +--- a/lib/libwtmpdb.c ++++ b/lib/libwtmpdb.c +@@ -38,6 +38,9 @@ + + #include "varlink.h" + ++#undef _PATH_WTMPDB ++#define _PATH_WTMPDB "/var/log/wtmp.db" ++ + #if WITH_WTMPDBD + static int varlink_is_active = 1; + #else +diff --git a/man/pam_wtmpdb.8.xml b/man/pam_wtmpdb.8.xml +index 2781648..54a2c4f 100644 +--- a/man/pam_wtmpdb.8.xml ++++ b/man/pam_wtmpdb.8.xml +@@ -36,7 +36,7 @@ + <para> + pam_wtmpdb is a PAM module to record the login and logout + information of the user. The module uses +- <filename>/var/lib/wtmpdb/wtmp.db</filename> as database ++ <filename>/var/log/wtmp.db</filename> as database + file to store all information. + </para> + <para> +@@ -90,7 +90,7 @@ + <listitem> + <para> + Use <option>file</option> instead of +- <filename>/var/lib/wtmpdb/wtmp.db</filename>. ++ <filename>/var/log/wtmp.db</filename>. + </para> + </listitem> + </varlistentry> +@@ -166,11 +166,20 @@ + <title>FILES</title> + <variablelist> + <varlistentry> +- <term>/var/lib/wtmpdb/wtmp.db</term> ++ <term>/var/log/wtmp.db</term> + <listitem> + <para>Wtmpdb logging database file</para> + </listitem> + </varlistentry> ++ <varlistentry> ++ <term>/var/lib/wtmpdb/wtmp.db</term> ++ <listitem> ++ <para> ++ Symbolic link from the upstream location to the above ++ database file ++ </para> ++ </listitem> ++ </varlistentry> + </variablelist> + </refsect1> + +diff --git a/man/wtmpdb.8.xml b/man/wtmpdb.8.xml +index ba4975b..04e1b06 100644 +--- a/man/wtmpdb.8.xml ++++ b/man/wtmpdb.8.xml +@@ -49,7 +49,7 @@ + <listitem> + <para> + <command>wtmpdb last</command> goes through the +- <filename>/var/lib/wtmpdb/wtmp.db</filename> database (or the ++ <filename>/var/log/wtmp.db</filename> database (or the + database designated by the <command>-f</command> option) and + displays a list of of all users logged in and logged out. The + output can be restricted to different patterns via various +@@ -242,7 +242,7 @@ + <listitem> + <para> + <command>wtmpdb boot</command> writes system boot times +- to the <filename>/var/lib/wtmpdb/wtmp.db</filename> database. ++ to the <filename>/var/log/wtmp.db</filename> database. + </para> + <title>boot options</title> + <varlistentry> +@@ -273,7 +273,7 @@ + <listitem> + <para> + <command>wtmpdb shutdown</command> writes system shutdown +- requests to the <filename>/var/lib/wtmpdb/wtmp.db</filename> ++ requests to the <filename>/var/log/wtmp.db</filename> + database. + </para> + <title>shutdown options</title> +@@ -295,7 +295,7 @@ + <listitem> + <para> + <command>wtmpdb rotate</command> exports old log entries +- to the <filename>/var/lib/wtmpdb/wtmp_yyyymmmdd.db</filename> ++ to the <filename>/var/log/wtmp_yyyymmmdd.db</filename> + database and removes these entries from the original one. + </para> + <title>rotate options</title> +@@ -331,7 +331,7 @@ + <listitem> + <para> + <command>wtmpdb import</command> imports legacy wtmp log +- files to the <filename>/var/lib/wtmpdb/wtmp.db</filename> ++ files to the <filename>/var/log/wtmp.db</filename> + database. + </para> + <title>import options</title> +@@ -378,11 +378,20 @@ + <title>FILES</title> + <variablelist> + <varlistentry> +- <term>/var/lib/wtmpdb/wtmp.db</term> ++ <term>/var/log/wtmp.db</term> + <listitem> + <para>Wtmpdb logging database file</para> + </listitem> + </varlistentry> ++ <varlistentry> ++ <term>/var/lib/wtmpdb/wtmp.db</term> ++ <listitem> ++ <para> ++ Symbolic link from the upstream location to the above ++ database file ++ </para> ++ </listitem> ++ </varlistentry> + </variablelist> + </refsect1> + +diff --git a/src/pam_wtmpdb.c b/src/pam_wtmpdb.c +index 8b5a24f..5aeaccb 100644 +--- a/src/pam_wtmpdb.c ++++ b/src/pam_wtmpdb.c +@@ -36,6 +36,9 @@ + + #include "wtmpdb.h" + ++#undef _PATH_WTMPDB ++#define _PATH_WTMPDB "/var/log/wtmp.db" ++ + #define WTMPDB_DEBUG 01 /* send info to syslog(3) */ + #define WTMPDB_QUIET 02 /* keep quiet about things */ + #define WTMPDB_SKIP 04 /* Skip if service is in skip list */ +diff --git a/tmpfiles.d/wtmpdb.conf b/tmpfiles.d/wtmpdb.conf +index f66548e..dcaf2a9 100644 +--- a/tmpfiles.d/wtmpdb.conf ++++ b/tmpfiles.d/wtmpdb.conf +@@ -3,3 +3,4 @@ + # See tmpfiles.d(5) for details + # + d /var/lib/wtmpdb 0755 - - - ++L /var/lib/wtmpdb/wtmp.db - - - - ../../log/wtmp.db +diff --git a/units/wtmpdb-rotate.service b/units/wtmpdb-rotate.service +index 7918857..465b659 100644 +--- a/units/wtmpdb-rotate.service ++++ b/units/wtmpdb-rotate.service +@@ -1,7 +1,7 @@ + [Unit] + Description=Rotate wtmpdb + Documentation=man:wtmpdb(8) +-RequiresMountsFor=/var/lib/wtmpdb ++RequiresMountsFor=/var/log + + [Service] + Type=oneshot +diff --git a/units/wtmpdb-update-boot.service b/units/wtmpdb-update-boot.service +index c46dcb9..bc16f7c 100644 +--- a/units/wtmpdb-update-boot.service ++++ b/units/wtmpdb-update-boot.service +@@ -2,7 +2,7 @@ + Description=Write boot and shutdown times into wtmpdb + Documentation=man:wtmpdb(8) + DefaultDependencies=no +-RequiresMountsFor=/var/lib/wtmpdb ++RequiresMountsFor=/var/log + Conflicts=shutdown.target + After=systemd-remount-fs.service systemd-tmpfiles-setup.service + Before=shutdown.target diff -Nru wtmpdb-0.73.0/debian/patches/import-match-login-by-tty-if-non-zero-pid-does-not-match.patch wtmpdb-0.75.0/debian/patches/import-match-login-by-tty-if-non-zero-pid-does-not-match.patch --- wtmpdb-0.73.0/debian/patches/import-match-login-by-tty-if-non-zero-pid-does-not-match.patch 2025-05-04 18:39:33.000000000 +0100 +++ wtmpdb-0.75.0/debian/patches/import-match-login-by-tty-if-non-zero-pid-does-not-match.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,27 +0,0 @@ -From: Andrew Bower <andrew@bower.uk> -Date: Wed, 9 Apr 2025 19:06:10 +0100 -Forwarded: https://github.com/thkukuk/wtmpdb/pull/37 -Applied-Upstream: commit:8a09bf99d79b79e9b83aea704d0eb1b5de55e3ea -Subject: import: match login by tty if non-zero pid does not match - -The existing code matches a utmp logout entry to a login entry by the preferred -pid method if possible and then by tty if the pid is zero. This does not -correspond to some servers that record the logout with a different value in the -pid field, resulting in the logout times being recorded as 'crash'. ---- - src/import.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/import.c b/src/import.c -index d03bd0c..b34a086 100644 ---- a/src/import.c -+++ b/src/import.c -@@ -114,7 +114,7 @@ import_utmp_records (const char *db_path, - { - if (v->ut_type == UTMP_USER_PROCESS && - ((u->ut_pid != 0 && v->ut_pid == u->ut_pid) || -- (u->ut_pid == 0 && strncmp (v->ut_line, u->ut_line, UT_LINESIZE) == 0))) -+ (strncmp (v->ut_line, u->ut_line, UT_LINESIZE) == 0))) - { - id = id_map[v - utmp_data]; - if (id > 0) diff -Nru wtmpdb-0.73.0/debian/patches/series wtmpdb-0.75.0/debian/patches/series --- wtmpdb-0.73.0/debian/patches/series 2025-05-04 18:39:33.000000000 +0100 +++ wtmpdb-0.75.0/debian/patches/series 2025-10-11 19:19:49.000000000 +0100 @@ -1,3 +1,3 @@ avoid-noise-if-systemd-not-running.patch refine-man-page-for-Debian.patch -import-match-login-by-tty-if-non-zero-pid-does-not-match.patch +db-in-var-log.patch diff -Nru wtmpdb-0.73.0/debian/README.Debian wtmpdb-0.75.0/debian/README.Debian --- wtmpdb-0.73.0/debian/README.Debian 2025-05-04 18:39:33.000000000 +0100 +++ wtmpdb-0.75.0/debian/README.Debian 2025-10-11 23:26:05.000000000 +0100 @@ -2,16 +2,18 @@ ---------------- In Debian 13 "trixie", login and reboot records are recorded by the 'wtmpdb' -solution in an sqlite3 database file. This document identifies differences in -behaviour since earlier Debian releases that may require action by system -administators. +solution in an sqlite3 database file, which can represent a larger ranger of +times. This document identifies differences in behaviour since earlier Debian +releases that may require action by system administators. Log location ------------ -The datafile for the login and reboot records is stored in the tool's state -directory '/var/lib/wtmpdb' instead of the system log directory '/var/log'. +The datafile for the login and reboot records is stored in the system log +directory '/var/log' instead of the tool's state directory '/var/lib/wtmpdb' as +defined upstream via /usr/include/wtmpdb.h. On Debian /var/lib/wtmpdb/wtmp.db +should be a symbolic link to /var/log/wtmp.db. Logging SSH sessions @@ -41,36 +43,23 @@ If old rotated log files like /var/log/wtmp.1 are present, these can be manually converted with the 'wtmpdb import' command (specify '-f' if these are -to be written to another file for archival rather than to the current login -database). On default configurations, there are unlikely to be any older +to be written to another file for archiving rather than merged into the current +login database). On default configurations, there are unlikely to be any older rotated files such as wtmp.2.gz but if there are, these can be uncompressed with gzip before being imported. +Note that automatic import of old records will not happen if the new database +file gets populated before the wtmpdb package is installed, which can happen if +ssh or console logins are recorded after the system upgrade but before the +wtmpdb package is installed. In this case the old file can be imported manually +as described above. + Log rotation and pruning ------------------------ -Logs can be rotated by the 'wtmpdb rotate' command. A systemd timer unit -is installed to do this on a monthly basis; however, this timer is not -enabled by default because of its limitations: - - 1. The rotated files are dated by the latest rotated entry in the form - wtmp_YYYYMMDD.db, rather than numerically like wtmp.1[.gz]. - - 2. The rotated files are saved alongside the live database in /var/lib, - contrary to what might be expected under the FHS 3.0 followed by Debian. - - 3. Rotated files are NOT pruned [1], as they would be by logrotate(8). - If you need to prune old logs then this will require custom scripts as - logrotate cannot be configured to achieve this. - -Use 'systemctl enable wtmpdb-rotate.timer' to enable rotation. - -Users needing to remove old login records for regulatory purposes will need to -implement a pruning function in addition to rotating the database. logrotate(8) -may be suitable for this purpose instead of the installed systemd timer. - -[1] https://bugs.debian.org/1094965 +Logs are rotated and pruned by logrotate(8). The rotation and retention +periods may be inspected and modified in /etc/logrotate.d/wtmpdb - -- Andrew Bower <andrew@bower.uk> Sun, 4 May 2025 18:10:00 +0100 + -- Andrew Bower <andrew@bower.uk> Sat, 04 Oct 2025 09:46:09 +0100 diff -Nru wtmpdb-0.73.0/debian/rules wtmpdb-0.75.0/debian/rules --- wtmpdb-0.73.0/debian/rules 2025-05-04 18:39:33.000000000 +0100 +++ wtmpdb-0.75.0/debian/rules 2025-10-11 15:00:41.000000000 +0100 @@ -18,12 +18,15 @@ # 1. Do not add a boot entry on installation because most likely we are # either not running in the target system or we have migrated the wtmp # boot entry and in all cases we did not just boot up. -# 2. Do not enable the rotation service because it provides no benefit: the -# rotated logs are not pruned, they simply become harder to interrogate. +# 2. Do not install the rotation service because log rotation is handled +# by logrotate(8) and the competing (half) solution would be especially +# harmful if boith methods were enabled by misconfiguration. override_dh_installsystemd: dh_installsystemd -pwtmpdb --no-start --no-stop-on-upgrade wtmpdb-update-boot.service - dh_installsystemd -pwtmpdb --no-enable wtmpdb-rotate.timer dh_installsystemd -Nwtmpdb override_dh_installinit: dh_installinit --name=wtmpdb-update-boot --no-start --no-stop-on-upgrade + +override_dh_installlogrotate: + dh_installlogrotate --name=wtmpdb diff -Nru wtmpdb-0.73.0/debian/wtmpdb.conffiles wtmpdb-0.75.0/debian/wtmpdb.conffiles --- wtmpdb-0.73.0/debian/wtmpdb.conffiles 1970-01-01 01:00:00.000000000 +0100 +++ wtmpdb-0.75.0/debian/wtmpdb.conffiles 2025-10-11 15:00:41.000000000 +0100 @@ -0,0 +1 @@ +remove-on-upgrade /etc/cron.monthly/wtmpdb diff -Nru wtmpdb-0.73.0/debian/wtmpdb.install wtmpdb-0.75.0/debian/wtmpdb.install --- wtmpdb-0.73.0/debian/wtmpdb.install 2025-05-04 18:39:33.000000000 +0100 +++ wtmpdb-0.75.0/debian/wtmpdb.install 2025-10-11 15:00:41.000000000 +0100 @@ -1,6 +1,4 @@ usr/bin/wtmpdb -usr/lib/systemd/system/wtmpdb-rotate.service -usr/lib/systemd/system/wtmpdb-rotate.timer usr/lib/systemd/system/wtmpdb-update-boot.service usr/lib/tmpfiles.d/wtmpdb.conf usr/share/man/man8/wtmpdb.8 diff -Nru wtmpdb-0.73.0/debian/wtmpdb.postinst wtmpdb-0.75.0/debian/wtmpdb.postinst --- wtmpdb-0.73.0/debian/wtmpdb.postinst 2025-05-04 18:39:33.000000000 +0100 +++ wtmpdb-0.75.0/debian/wtmpdb.postinst 2025-10-11 15:00:41.000000000 +0100 @@ -11,7 +11,7 @@ fi old_log="${DPKG_ROOT:-}/var/log/wtmp" -new_log="${DPKG_ROOT:-}/var/lib/wtmpdb/wtmp.db" +new_log="${DPKG_ROOT:-}/var/log/wtmp.db" tmp_log="$new_log.import-tmp" # If wtmp logs are present on first installation, import them. diff -Nru wtmpdb-0.73.0/lib/sqlite.c wtmpdb-0.75.0/lib/sqlite.c --- wtmpdb-0.73.0/lib/sqlite.c 2025-04-08 14:18:16.000000000 +0100 +++ wtmpdb-0.75.0/lib/sqlite.c 2025-10-09 14:18:36.000000000 +0100 @@ -61,16 +61,41 @@ } } +/* Creates the table if it does not exist. + * Returns 0 on success, -1 on failure. */ +static int64_t +create_table (sqlite3 *db, char **error) +{ + char *err_msg = NULL; + char *sql_table = "CREATE TABLE IF NOT EXISTS wtmp(ID INTEGER PRIMARY KEY, Type INTEGER, User TEXT NOT NULL, Login INTEGER, Logout INTEGER, TTY TEXT, RemoteHost TEXT, Service TEXT) STRICT;"; + + if (sqlite3_exec (db, sql_table, 0, 0, &err_msg) != SQLITE_OK) + { + if (error) + if (asprintf (error, "SQL error creating table: %s", err_msg) < 0) + *error = strdup ("create_table: Out of memory"); + sqlite3_free (err_msg); + + return -1; + } + return 0; +} + static int open_database_ro (const char *path, sqlite3 **db, char **error) { + struct stat statbuf; + int empty_file; int r; - r = sqlite3_open_v2 (path, db, SQLITE_OPEN_READONLY, NULL); + empty_file = stat(path, &statbuf) == 0 && statbuf.st_size == 0; + r = sqlite3_open_v2 (path, db, empty_file ? + SQLITE_OPEN_READWRITE | SQLITE_OPEN_MEMORY : + SQLITE_OPEN_READONLY, NULL); if (r != SQLITE_OK) { if (error) - if (asprintf(error, "open_database_ro: Cannot open database (%s): %s", + if (asprintf(error, "Cannot open database (%s) read-only: %s", path, sqlite3_errmsg(*db)) < 0) *error = strdup("open_database_ro: Out of memory"); sqlite3_close(*db); @@ -80,7 +105,10 @@ sqlite3_busy_timeout(*db, TIMEOUT); - return 0; + if (empty_file) + r = create_table (*db, error); + + return r == SQLITE_OK ? 0 : -1; } static int @@ -103,7 +131,7 @@ if (r != SQLITE_OK) { if (error) - if (asprintf (error, "open_database_rw: Cannot create/open database (%s): %s", + if (asprintf (error, "Cannot create/open database (%s): %s", path, sqlite3_errmsg (*db)) < 0) *error = strdup ("open_database_rw: Out of memory"); @@ -114,7 +142,8 @@ sqlite3_busy_timeout(*db, TIMEOUT); - return 0; + r = create_table (*db, error); + return r == SQLITE_OK ? 0 : -1; } /* Add a new entry. Returns ID (>=0) on success, -1 on failure. */ @@ -123,25 +152,13 @@ uint64_t usec_login, const char *tty, const char *rhost, const char *service, char **error) { - char *err_msg = NULL; sqlite3_stmt *res; - char *sql_table = "CREATE TABLE IF NOT EXISTS wtmp(ID INTEGER PRIMARY KEY, Type INTEGER, User TEXT NOT NULL, Login INTEGER, Logout INTEGER, TTY TEXT, RemoteHost TEXT, Service TEXT) STRICT;"; char *sql_insert = "INSERT INTO wtmp (Type,User,Login,TTY,RemoteHost,Service) VALUES(?,?,?,?,?,?);"; - if (sqlite3_exec (db, sql_table, 0, 0, &err_msg) != SQLITE_OK) - { - if (error) - if (asprintf (error, "add_entry: SQL error: %s", err_msg) < 0) - *error = strdup ("add_entry: Out of memory"); - sqlite3_free (err_msg); - - return -1; - } - if (sqlite3_prepare_v2 (db, sql_insert, -1, &res, 0) != SQLITE_OK) { if (error) - if (asprintf (error, "add_entry: Failed to execute statement: %s", + if (asprintf (error, "Failed to prepare statement (add_entry): %s", sqlite3_errmsg (db)) < 0) *error = strdup ("add_entry: Out of memory"); @@ -151,7 +168,7 @@ if (sqlite3_bind_int (res, 1, type) != SQLITE_OK) { if (error) - if (asprintf (error, "add_entry: Failed to create replace statement for type: %s", + if (asprintf (error, "Failed to create add statement for 'type': %s", sqlite3_errmsg (db)) < 0) *error = strdup("add_entry: Out of memory"); @@ -162,7 +179,7 @@ if (sqlite3_bind_text (res, 2, user, -1, SQLITE_STATIC) != SQLITE_OK) { if (error) - if (asprintf (error, "add_entry: Failed to create replace statement for user: %s", + if (asprintf (error, "Failed to create add statement for 'user': %s", sqlite3_errmsg (db)) < 0) *error = strdup ("add_entry: Out of memory"); @@ -173,7 +190,7 @@ if (sqlite3_bind_int64 (res, 3, usec_login) != SQLITE_OK) { if (error) - if (asprintf (error, "add_entry: Failed to create replace statement for login time: %s", + if (asprintf (error, "Failed to create add statement for 'login' time (add_entry): %s", sqlite3_errmsg (db)) < 0) *error = strdup("add_entry: Out of memory"); @@ -184,7 +201,7 @@ if (sqlite3_bind_text (res, 4, tty, -1, SQLITE_STATIC) != SQLITE_OK) { if (error) - if (asprintf (error, "add_entry: Failed to create replace statement for tty: %s", + if (asprintf (error, "Failed to create add statement for 'tty': %s", sqlite3_errmsg (db)) < 0) *error = strdup("add_entry: Out of memory"); @@ -195,7 +212,7 @@ if (sqlite3_bind_text (res, 5, rhost, -1, SQLITE_STATIC) != SQLITE_OK) { if (error) - if (asprintf (error, "add_entry: Failed to create replace statement for rhost: %s", + if (asprintf (error, "Failed to create add statement for 'rhost': %s", sqlite3_errmsg (db)) < 0) *error = strdup("add_entry: Out of memory"); @@ -206,7 +223,7 @@ if (sqlite3_bind_text (res, 6, service, -1, SQLITE_STATIC) != SQLITE_OK) { if (error) - if (asprintf (error, "add_entry: Failed to create replace statement for service: %s", + if (asprintf (error, "Failed to create add statement for 'service': %s", sqlite3_errmsg (db)) < 0) *error = strdup("add_entry: Out of memory"); @@ -219,8 +236,8 @@ if (step != SQLITE_DONE) { if (error) - if (asprintf (error, "add_entry: Adding an entry did not return SQLITE_DONE: %d", - step) < 0) + if (asprintf (error, "Adding an entry failed: %s", + sqlite3_errstr(step)) < 0) *error = strdup("add_entry: Out of memory"); sqlite3_finalize(res); @@ -269,7 +286,7 @@ if (sqlite3_prepare_v2 (db, sql, -1, &res, 0) != SQLITE_OK) { if (error) - if (asprintf (error, "update_logout: Failed to execute statement: %s", + if (asprintf (error, "Failed to prepare statement (update_logout): %s", sqlite3_errmsg (db)) < 0) *error = strdup ("update_logout: Out of memory"); @@ -279,7 +296,7 @@ if (sqlite3_bind_int64 (res, 1, usec_logout) != SQLITE_OK) { if (error) - if (asprintf (error, "update_logout: Failed to create update query (logout): %s", + if (asprintf (error, "Failed to create update query (logout): %s", sqlite3_errmsg (db)) < 0) *error = strdup("update_logout: Out of memory"); @@ -290,7 +307,7 @@ if (sqlite3_bind_int64 (res, 2, id) != SQLITE_OK) { if (error) - if (asprintf (error, "update_logout: Failed to create update query (ID): %s", + if (asprintf (error, "Failed to create update query (ID): %s", sqlite3_errmsg (db)) < 0) *error = strdup("update_logout: Out of memory"); @@ -303,8 +320,8 @@ if (step != SQLITE_DONE) { if (error) - if (asprintf (error, "update_logout: Updating logout time did not return SQLITE_DONE: %d", - step) < 0) + if (asprintf (error, "Updating logout time failed: %s", + sqlite3_errstr(step)) < 0) *error = strdup("update_logout: Out of memory"); sqlite3_finalize(res); @@ -315,7 +332,7 @@ if ((changes = sqlite3_changes (db)) != 1) { if (error) - if (asprintf (error, "update_logout: Updated wrong number of rows, expected 1, got %d", + if (asprintf (error, "Update of logout time changed wrong number of rows, expected 1, got %d", changes) < 0) *error = strdup("update_logout: Out of memory"); @@ -364,7 +381,7 @@ { int r = -ENOTSUP; if (error) - if (asprintf (error, "search_id: Failed to execute statement: %s", + if (asprintf (error, "Failed to prepare statement (search_id): %s", sqlite3_errmsg (db)) < 0) { r = -ENOMEM; @@ -377,7 +394,7 @@ { int r = -EPROTO; if (error) - if (asprintf (error, "search_id: Failed to create search query: %s", + if (asprintf (error, "Failed to create search query 'tty': %s", sqlite3_errmsg (db)) < 0) { r = -ENOMEM; @@ -396,7 +413,7 @@ { id = -ENOENT; if (error) - if (asprintf (error, "search_id: Open entry for tty '%s' not found", tty) < 0) + if (asprintf (error, "Open entry for tty '%s' not found (search_id)", tty) < 0) { *error = strdup("search_id: Out of memory"); id = -ENOMEM; @@ -406,7 +423,8 @@ { id = -ENOENT; if (error) - if (asprintf (error, "search_id: sqlite3_step returned: %d", step) < 0) + if (asprintf (error, "Error searching open entry for tty '%s': %s", + tty, sqlite3_errstr(step)) < 0) { *error = strdup("search_id: Out of memory"); id = -ENOMEM; @@ -567,7 +585,7 @@ if (sqlite3_prepare_v2 (db_src, sql_select, -1, &res, 0) != SQLITE_OK) { if (error) - if (asprintf (error, "sqlite_rotate: Failed to execute statement %s: %s", + if (asprintf (error, "Failed to prepare statement %s (sqlite_rotate): %s", sql_select, sqlite3_errmsg (db_src)) < 0) *error = strdup ("sqlite_rotate: Out of memory"); @@ -581,7 +599,7 @@ if (sqlite3_bind_int64 (res, 1, login_t) != SQLITE_OK) { if (error) - if (asprintf (error, "sqlite_rotate: Failed to create replace statement for login time: %s", + if (asprintf (error, "Failed to create rotate statement for 'login' time: %s", sqlite3_errmsg (db_src)) < 0) *error = strdup("sqlite_rotate: Out of memory"); @@ -600,7 +618,7 @@ } if (rc != SQLITE_DONE) { - if (asprintf (error, "sqlite_rotate: SQL error: %s", sqlite3_errmsg(db_src)) < 0) + if (asprintf (error, "SQL error rotating db: %s", sqlite3_errmsg(db_src)) < 0) *error = strdup ("sqlite_rotate: Out of memory"); sqlite3_finalize(res); @@ -617,7 +635,7 @@ if (sqlite3_prepare_v2 (db_src, sql_delete, -1, &res, 0) != SQLITE_OK) { if (error) - if (asprintf (error, "sqlite_rotate: Failed to execute statement %s: %s", + if (asprintf (error, "Failed to prepare statement %s (sqlite_rotate): %s", sql_delete, sqlite3_errmsg (db_src)) < 0) *error = strdup ("sqlite_rotate: Out of memory"); @@ -631,7 +649,7 @@ if (sqlite3_bind_int64 (res, 1, login_t) != SQLITE_OK) { if (error) - if (asprintf (error, "sqlite_rotate: Failed to create replace statement for login time: %s", + if (asprintf (error, "Failed to create rotate statement for 'login' time: %s", sqlite3_errmsg (db_src)) < 0) *error = strdup("sqlite_rotate: Out of memory"); @@ -648,8 +666,8 @@ if (step != SQLITE_DONE) { if (error) - if (asprintf (error, "sqlite_rotate: Adding an entry did not return SQLITE_DONE: %d", - step) < 0) + if (asprintf (error, "Error rotating entry: %s", + sqlite3_errstr(step)) < 0) *error = strdup("sqlite_rotate: Out of memory"); sqlite3_finalize(res); @@ -690,7 +708,7 @@ if (sqlite3_prepare_v2 (db, sql, -1, &res, 0) != SQLITE_OK) { if (error) - if (asprintf (error, "search_boottime: Failed to execute statement: %s", + if (asprintf (error, "Failed to prepare statement (search_boottime): %s", sqlite3_errmsg (db)) < 0) *error = strdup ("search_boottime: Out of memory"); @@ -704,7 +722,8 @@ else { if (error) - if (asprintf (error, "search_boottime: Boot time not found (%d)", step) < 0) + if (asprintf (error, "Boot time not found: %s", + sqlite3_errstr(step)) < 0) *error = strdup("search_boottime: Out of memory"); sqlite3_finalize (res); diff -Nru wtmpdb-0.73.0/lib/varlink.c wtmpdb-0.75.0/lib/varlink.c --- wtmpdb-0.73.0/lib/varlink.c 2025-04-08 14:18:16.000000000 +0100 +++ wtmpdb-0.75.0/lib/varlink.c 2025-10-09 14:18:36.000000000 +0100 @@ -313,7 +313,7 @@ else *error = strdup(error_id); } - if (strcmp(error_id, "org.openSUSE.rebootmgr.NoEntryFound") == 0) + if (strcmp(error_id, "org.openSUSE.wtmpdb.NoEntryFound") == 0) return -ENOENT; else return -EIO; @@ -388,7 +388,7 @@ else *error = strdup(error_id); } - if (strcmp(error_id, "org.openSUSE.rebootmgr.NoEntryFound") == 0) + if (strcmp(error_id, "org.openSUSE.wtmpdb.NoEntryFound") == 0) return -ENOENT; else return -EIO; diff -Nru wtmpdb-0.73.0/meson.build wtmpdb-0.75.0/meson.build --- wtmpdb-0.73.0/meson.build 2025-04-08 14:18:16.000000000 +0100 +++ wtmpdb-0.75.0/meson.build 2025-10-09 14:18:36.000000000 +0100 @@ -12,7 +12,7 @@ 'b_lto=true', 'warning_level=2'], license : ['BSD-2-Clause'], - version : '0.73.0', + version : '0.75.0', ) conf = configuration_data() diff -Nru wtmpdb-0.73.0/NEWS wtmpdb-0.75.0/NEWS --- wtmpdb-0.73.0/NEWS 2025-04-08 14:18:16.000000000 +0100 +++ wtmpdb-0.75.0/NEWS 2025-10-09 14:18:36.000000000 +0100 @@ -1,3 +1,11 @@ +Version 0.75.0 +* Use empty memory table instead of failing to read empty file +* libwtmpdb: enhance/unify error messages + +Version 0.74.0 +* Fix varlink interface name (rebootmgr vs wtmpdb) +* import: match login by tty if non-zero pid does not match + Version 0.73.0 * Expand accepted time format options (-p) * Use documented -t short option for last --until diff -Nru wtmpdb-0.73.0/src/import.c wtmpdb-0.75.0/src/import.c --- wtmpdb-0.73.0/src/import.c 2025-04-08 14:18:16.000000000 +0100 +++ wtmpdb-0.75.0/src/import.c 2025-10-09 14:18:36.000000000 +0100 @@ -114,7 +114,7 @@ { if (v->ut_type == UTMP_USER_PROCESS && ((u->ut_pid != 0 && v->ut_pid == u->ut_pid) || - (u->ut_pid == 0 && strncmp (v->ut_line, u->ut_line, UT_LINESIZE) == 0))) + (strncmp (v->ut_line, u->ut_line, UT_LINESIZE) == 0))) { id = id_map[v - utmp_data]; if (id > 0) diff -Nru wtmpdb-0.73.0/src/wtmpdbd.c wtmpdb-0.75.0/src/wtmpdbd.c --- wtmpdb-0.73.0/src/wtmpdbd.c 2025-04-08 14:18:16.000000000 +0100 +++ wtmpdb-0.75.0/src/wtmpdbd.c 2025-10-09 14:18:36.000000000 +0100 @@ -250,7 +250,7 @@ if (id < 0 || error != NULL) { log_msg(LOG_ERR, "Get ID request from db failed: %s", error); - return sd_varlink_errorbo(link, "org.openSUSE.rebootmgr.InternalError", + return sd_varlink_errorbo(link, "org.openSUSE.wtmpdb.InternalError", SD_JSON_BUILD_PAIR_STRING("ErrorMsg", error)); } @@ -307,7 +307,7 @@ { /* let wtmpdb_logout return better error codes, e.g. not found vs real error */ log_msg(LOG_ERR, "Logout request from db failed: %s", error); - return sd_varlink_errorbo(link, "org.openSUSE.rebootmgr.InternalError", + return sd_varlink_errorbo(link, "org.openSUSE.wtmpdb.InternalError", SD_JSON_BUILD_PAIR_BOOLEAN("Success", false), SD_JSON_BUILD_PAIR_STRING("ErrorMsg", error)); @@ -357,7 +357,7 @@ if (id < 0 || error != NULL) { log_msg(LOG_ERR, "Get ID request from db failed: %s", error); - return sd_varlink_errorbo(link, "org.openSUSE.rebootmgr.NoEntryFound", + return sd_varlink_errorbo(link, "org.openSUSE.wtmpdb.NoEntryFound", SD_JSON_BUILD_PAIR_STRING("ErrorMsg", error)); } @@ -390,7 +390,7 @@ if (boottime == 0 || error != NULL) { log_msg(LOG_ERR, "Get boottime from db failed: %s", error); - return sd_varlink_errorbo(link, "org.openSUSE.rebootmgr.NoEntryFound", + return sd_varlink_errorbo(link, "org.openSUSE.wtmpdb.NoEntryFound", SD_JSON_BUILD_PAIR_BOOLEAN("Success", false), SD_JSON_BUILD_PAIR_STRING("ErrorMsg", error)); @@ -494,7 +494,7 @@ if (r < 0 || error != NULL || incomplete) { log_msg(LOG_ERR, "Didn't got all entries from db: %s", error); - return sd_varlink_errorbo(link, "org.openSUSE.rebootmgr.InternalError", + return sd_varlink_errorbo(link, "org.openSUSE.wtmpdb.InternalError", SD_JSON_BUILD_PAIR_BOOLEAN("Success", false), SD_JSON_BUILD_PAIR_STRING("ErrorMsg", error?error:"unknown")); @@ -551,7 +551,7 @@ if (r < 0 || error != NULL) { log_msg(LOG_ERR, "Rotate db failed: %s", error); - return sd_varlink_errorbo(link, "org.openSUSE.rebootmgr.NoEntryFound", + return sd_varlink_errorbo(link, "org.openSUSE.wtmpdb.NoEntryFound", SD_JSON_BUILD_PAIR_BOOLEAN("Success", false), SD_JSON_BUILD_PAIR_STRING("ErrorMsg", error)); }
Attachment:
signature.asc
Description: PGP signature