This is the mail archive of the mailing list for the glibc project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: utmp

Hi Arnd,

Le Tue, 28 Jun 2016 23:49:11 +0200, Arnd Bergmann <> a
Ãcrit :

> On Tuesday, June 28, 2016 11:08:53 PM CEST Albert ARIBAUD wrote:
> > OK, so, to sum up on utmp.
> > 
> > This is what we want:
> > 
> > - the utmp file structure should not depend on architecture word size
> >   or, ideally, endianness.
> > 
> > - the utmp/utmpx APIs should be conforming to POSIX.
> > 
> > - the utmp[x] struct should not depend on kernel types.
> > 
> > Here is a possible solution:
> > 
> > 1. Create a separate utmp structure for the utmp file.
> > 
> > 2. Make the file utmp struct's ut_tv.tv_sec field a signed 64-bit int
> >    unconditionally, and ideally, its endianness should be constant.
> > 
> > 3. The API utmp[x] struct's ut_tv field would be a struct timeval as
> >    expected by POSIX.
> > 
> > 4. GLIBC would translate between API utmp[x] structs and file utmp
> >    struct, both endianness and size. When translating a 64-bit tv_sec
> >    into a 32-bit tv_sec, if the value would overflow, then errno would
> >    be set to EOVERFLOW and a failure value would be returned.
> > 
> > 5. Upgrade path for a 'new' glibc where the 'old' and 'new' utmp file
> >    formats are different in size, endianness or both: this would be best
> >    handled by the packaging system, all the more since there may also be
> >    dependency constraints involving some utilities which depend on the
> >    utmp file structure, like utmpdump.  
> Nothing wrong with this approach, just another idea from how we handle
> upgrading on-disk structures elsewhere:
> In ext4, we use the two upper bits of the 32-bit nanoseconds to
> extend the seconds. This way a structure that stores signed
> seconds as 32 bit and can normally represent the range between 1902
> and 2038 gets extended by another 3*136 years, so we can go until
> 2446 with a backwards-compatible extension. If we treat the on-disk
> seconds as unsigned (we know that pre-1970 times are all guaranteed
> to be invalid for utmp), we get another 68 years.
> Obviously this is a trick that only works when you have full control
> over all code that reads or writes the timestamps, and it doesn't
> solve the endianess problem, but it avoids introducing an incompatible
> format. Also, there is no reason for new architectures to do that,
> they should just do what you describe above.

As far as choosing between tricks, I would favor switching to an
unsigned 32-bit timestamp, which would be much simpler to code and less
run-time-error prone.

But this only buys us more time beyond Y2038 just to make a clean
transition to the full-64-bit solution, and we already have 22 years
for that, and in my experience, pushing the 'doomsdate' further back
just makes the issue more likely to be considered SEP and not be fixed
in time.

Plus, this transition would still be temporary, and we would still need
a transition from the 'old' (now 'possibly extended') format to the
'new' one.

Therefore, I would prefer avoiding any transitional state in which the
'old' format is 'just tweaked to allow for some time extension', and I
would prefer to transition straight from the current utmp file format
to the 64-bit time format.

Note: transitioning wtmp and btmp would be much easier, as they are log
files which can be rotated. The problem is with utmp because it is a
state file.

Actually, the problem is only between a GLIBC upgrade and the next
reboot, where utmp will be re-created, including the shutdown phase
itself, where some code might want to access the ('old') utmp file but
might accidentally use the new GLIBC.

A solution could be to reserve utmp, wtmp and btmp for the 'old' format
files and use utmpx, wtmpx and btmpx for the 'new' format files (which
would better match the POSIX header and struct name btw), keep the
'old' API implementations alongside the 'new' ones, and choose 'old' or
'new' as follows:

- (future) nominal case: if the utmp file does not exist, only use the
  utmpx file.

- transitioning: if the utmp file exists, use it for reading, and write
  to both the utmp and utmpx files.


- as long as the utmp file exists (and as long as we don't reach
  Y2038...) the system remains (as) compatible (as it was before) with
  any application code written to handle utmp records.

- development versions of applications which read utmp can be tested
  against the utmpx file while the system itself still runs on the utmp

- transitioning is under system control: remove utmp when the whole
  system is ready for it.


- this forces the GLIBC utmp code to keep the 'old' code for some
  time, which is a code phrase for 'future bitrot'.

- this doubles utmp-related file I/O. This might not be desirable on
  systems where there is a high rate of logins and logouts.

While we cannot avoid bitrot, we can at least make sure the whole
compatible code is kept within conditionals so that it can be easily
disabled, then removed; the trigger for disabling/removing should be
explicitly stated (in code as well as in docs) as "make sure this
is removed before Y2038 happens".

Regarding the file I/O rise, it cannot be avoided, and will have to be
contained by planning the system upgrade so that the transition is as
short as possible.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]