On Sat, Aug 23, 2025 at 12:38:42AM +0200, [email protected] wrote:
> On Fri, Aug 22, 2025 at 07:09:07PM +0100, Andrew Bower wrote:
> > On Thu, Aug 21, 2025 at 02:52:50PM +0200, g1 wrote:
> > > What about imitating the /etc/logrotate.d/wtmp file shipped by logrotate?
> > 
> > I have been mulling on this for a while in case any reasons came up why
> > this was a bad idea. I think it's the best one.
[...]
> I agree with you that the current combination of "rotate", "monthly" and
> "minsize" parameters can yield very different (and unpredictable) rotation
> intervals depending on system use: probably the best course of action is
> to provide a minimal viable configuration to prevent infinite growth, and
> let system administrators adapt it to their needs (technical or legal).

Yes.

> In fact, the minsize can be misleading, since the wtmp db (space-efficient
> sqlite) grows much more slowly than the legacy wtmp file (fixed format
> records).

Yes - looking at records from one host (with 1002-day uptime!), 5 years
of records in one file come to 756K in wtmp format and 80K when
converted to wtmpdb! So I think we should drop the size requirement but
also make it yearly - it only makes it harder to review what happened
across a boundary that happens 12 times per year and if you have
regulatory needs, just set it to exactly what you need!

[...]
> > I, too, think the rotated logs belong in /var/log - feels like an FHS
> > violation to keep them in the /var/lib where they could be lost
> > unintentionally (or incompetently - I just deleted by wtmp.db while
> > testing out things related to your suggestion!)
> > 
> > However, when I sounded out some other people on log rotation there was
> > a suggestion that mixing the locations was bad. I'm still open to it,
> > though!
> 
> I'm wondering what happens if /var/lib/wtmpdb/wtmp.db is replaced with
> a symlink to /var/log/wtmp.db.  If it works smoothly, then "what happens
> in /var/log stays in /var/log" and /var/lib gets rid of a log file
> in disguise.

I see your thinking! But I'm not sure that extra fragility is worth it,
do you? I'm leaning towards going with your 'olddir' setting with no
symlink.

> > > }
> > 
> > There is also the question of the post-rotation step: 'last' will report
> > an error on a non-existent file: should we seed the next one with
> > 'wtmpdb boot'?
> > 
> >   $ wtmpdb boot -f foo
> >   Boot time too far in the past, using current time:
> >   Boot time: Fri Aug 22 18:51:05 2025
> >   Current time: Fri Aug 22 19:06:46 2025
> >   $ last -f foo
> >   s-reboot system boot  6.12.38+deb13-am Fri Aug 22 19:06 - still running
> > 
> >   foo begins Fri Aug 22 19:06:46 2025
> >   $ last -f bar
> >   open_database_ro: Cannot open database (bar): unable to open database file
> 
> Personally, I'd prefer to get an error instead of a "synthetic" boot event.
> 
> As an alternative, wtmpdb could ship a wtmp-empty.db file (an empty sqlite
> db with the correct schema), and replace the removed wtmp.db with that
> file in the postrotate action of the logrotate snippet.

I don't think I want to ship a generated datafile and unfortunately
there is nothing in the wtmpdb interface that would initialise an empty
file (even import of nothing cannot do it!) so I think our options are:

 1. Get an error from empty file (status quo if we just add logrotate).

 2. Get the synthetic boot entry, but lose current sessions.

 3. Patch wtmpdb to do a special rotation that retains just the sessions
    from the current boot.

 4. Patch wtmpdb to gain a special 'initialise empty file' operation.

 5. Patch wtmpdb to give a benign output on non-existent file.

 6. Patch wtmpdb to give a benign output on zero-length file.

These have pros and cons:

 1. Get an error from empty file (status quo if we just add logrotate).

I think this is unacceptable.

 2. Get the synthetic boot entry, but lose current sessions.

I think this is pretty reasonable. So far as I am concerned "s-reboot"
is not a real thing, so I read it as a sentinel value, but I can see it
might confuse people so there is a risk here.

 3. Patch wtmpdb to do a special rotation that retains just the sessions
    from the current boot.

This could be done by adding features to the wtmpdb_rotate() shared library
function but even if this can be done backwards compatibly or with a new
function, upstream is pretty resistent to touching anything here so I
don't think that is going to fly.

It could be done by iterating through the entries - the 'import'
operation is implemented as a client of the library. That's going to be
slow because it has to be reopened for each row. We'd have to see how
well this worked, anyway.

 4. Patch wtmpdb to gain a special 'initialise empty file' operation.

This would be pretty neat. Currently you could do it I think by
contriving an insertion to fail, but that's horrible. I can't think just
yet of a change to the shared library that would be tolerable upstream
for this but it's just possible that a narrow path exists to a minimal
patch that was viable to sustain.

We could copy the SQL command and calls to outside the library but this
starts to get ugly too.

 5. Patch wtmpdb to give a benign output on non-existent file.

Probably it ought to fail with a non-existent file.

 6. Patch wtmpdb to give a benign output on zero-length file.

This is the simplest thing we could do for a sane outcome and I think
worth doing.

So where does that lead us?

My suggestion:

  4 (iff neat) > 3 (iff neat) > 6 > 2 > 5 > 1

Which means in practise "do 6" then maybe try 4 or 3 later if time and
the solution is clean and small.

That then combines with:

/var/lib/wtmpdb/wtmp.db {
    missingok
    yearly
    create
    nocompress
    rotate 4
    olddir /var/log
}

Arguably, the simplest of everything discussed!

Andrew


P.S. When reviewing before sending I had a sudden change of mind that
maybe I do like your generated file idea, which is like a static verion
of (4)... it could be generated with the sqlite3 command at build time.
But this'll have to stay as an addendum to my carefully crafted list!
:-)

Reply via email to