freebsd-update not updating reported patchlevel

Robert Bonomi bonomi at mail.r-bonomi.com
Fri May 4 16:43:53 UTC 2012


Polytropon <freebsd at edvax.de> wrote:
> On Fri, 4 May 2012 04:14:05 -0500 (CDT), Robert Bonomi wrote:
> > What is required is a differentation between the _kernel_ revision level,
> > and the patchlevel of the entire base system.
> > 
> > Store the kernel revision level -in- the kernel.  Use the 'standard'
> > THREE-level version numbering  {Major}.{Minor}.{revision} for the kernel.
> > Bump 'revision' for each set fo kernel patches.
> > 
> > The patchlevel info for the base system can be a simple data file.
> > I'd suggest a dotfile' in /etc, mode 644, with the followig flags
> > set: 'system append only', 'system undlink'.
> > 
> > Bump 'patchlevel' every time -anything- in the base system changes,
> > regardless of whether it is part of the kernel or the 'world'.
>
> Interesting approach. Both files could also be header files
> in /usr/include to store this information per #define. But
> in fact, I like the /etc idea better.

The 'state of the kernel' _belongs_ in /usr/src/sys, or similar. to be
included in kernal builds, and where the *handful* of utilities -- e.g. 
lsof -- that are intimately coupled to the exact O/S version are already
picking up 'system specific' gory details. 

/usr/include is definitely a 'wrong place'.  Arguably, so is /etc. 
 From the standpoint of 'a single place' for critical data, anything other 
than a kernel build should use what is in the 'uname' output. (See the
notes on O'Brien, below.)

_Very_few_ applications are concerned with the patchlevel of 'world'.
rebuilding everything that #included a 'world patchlevel' file, when
the only thing that changed was the patchlevel, is just plain silly.

> Allow me to extent the approach: For -STABLE versions (e. g. if
> updated per CVS), those files could contain the "build number"
> and the date of the currently installed -STABLE "snapshot".

Changes for 'other than that application' are -irrelevant- to any
particular application.

*PROPERLY* USED, CVS keywords provide automatic inclusion of this 
information -- for _every_ source module (.c or .h, and equivalents for
other languages) in every executable build.

For example, put the following lines in the start of every source module 
(before any '#include' lines);

 static char *_id =
  " @(#)      $Id:$  " "\0\0"
  " @(#)         Version: $Revision:$ Edited: $Date:$ " "\0\0"
  " @(#)         Build:   " __DATE__ " " __TIME__ " ";

and similar lines in each #include (excluding the 'build' info),
with the variable name being made 'unique' by appendinng the file name, 
and bracketed in #ifndef/#endif to ensure only a single inclusion in a
given mudule.  
  Recognizing that '@(#)' is a 'magic sequence' used by SCCS, and utilized
  by what(1).  if 'what' is not available, it can be simulated by;
    strings {foo} | awk '/^@(#) / { $1=""; print; }'

Add a similarly-constructed '_id_header' in the 'main' module, (making sure 
that 'main' is named first on the linker line) which provides a label, the 
'published' Major/minor/revision number and a 'counter' of the number of 
builds (doe with a one-liner addition in the makefile target that builds the
 executable, and you get results like THIS:

% what milter_daemon

milter_daemon:
	 version-control
	   Version: 1.1.0(368)
	   ----------------
	      milter_daemon.c,v 1.34 2010/11/04 23:54:02 bonomi Exp  
	         Version: 1.34 Edited: 2010/11/04 23:54:02 
	         Build:   Dec 20 2010 02:49:47 
	        testharness.h,v 1.5 2010/11/04 23:53:37 bonomi Exp  
	           Version: 1.5 Edited: 2010/11/04 23:53:37 
	        milter_includes.h,v 1.5 2010/11/04 23:53:37 bonomi Exp  
	           Version: 1.5 Edited: 2010/11/04 23:53:37 
	        pass_dict.h,v 1.4 2010/11/04 23:53:37 bonomi Exp  
	           Version: 1.4 Edited: 2010/11/04 23:53:37 
	        headers.h,v 1.4 2010/10/02 00:12:56 bonomi Exp  
	           Version: 1.4 Edited: 2010/10/02 00:12:56 
	        mime_subs.h,v 1.4 2010/11/04 23:53:37 bonomi Exp  
	           Version: 1.4 Edited: 2010/11/04 23:53:37 
	        milter_config_file.h,v 1.25 2010/11/27 21:43:02 bonomi Exp  
	           Version: 1.25 Edited: 2010/11/27 21:43:02 
	        postfixer.h,v 1.8 2010/11/04 23:53:37 bonomi Exp  
	           Version: 1.8 Edited: 2010/11/04 23:53:37 
	        mlfi_priv.h,v 1.9 2010/10/05 16:18:15 bonomi Exp  
	           Version: 1.9 Edited: 2010/10/05 16:18:15 
	        checklists.h,v 1.3 2010/09/16 18:27:51 bonomi Exp  
	           Version: 1.3 Edited: 2010/09/16 18:27:51 
	        per_user_config.h,v 1.2 2010/10/25 22:45:37 bonomi Exp  
	           Version: 1.2 Edited: 2010/10/25 22:45:37 
	      pass_dictionary.c,v 1.5 2010/11/04 23:54:02 bonomi Exp  
	         Version: 1.5 Edited: 2010/11/04 23:54:02 
	         Build:   Dec 20 2010 02:49:49 
	      headers.c,v 1.4 2010/10/02 00:12:56 bonomi Exp  
	         Version: 1.4 Edited: 2010/10/02 00:12:56 
	         Build:   Dec 20 2010 02:49:52 
	        headers.h,v 1.4 2010/10/02 00:12:56 bonomi Exp  
	           Version: 1.4 Edited: 2010/10/02 00:12:56 
	      mime_subs.c,v 1.5 2010/11/04 23:54:02 bonomi Exp  
	         Version: 1.5 Edited: 2010/11/04 23:54:02 
	         Build:   Dec 20 2010 02:49:52 
	        mime_subs.h,v 1.4 2010/11/04 23:53:37 bonomi Exp  
	           Version: 1.4 Edited: 2010/11/04 23:53:37 
	      shm_subs.c,v 1.10 2010/11/04 23:54:02 bonomi Exp  
	         Version: 1.10 Edited: 2010/11/04 23:54:02 
	         Build:   Dec 20 2010 02:49:46 
	        milter_config_file.h,v 1.25 2010/11/27 21:43:02 bonomi Exp  
	           Version: 1.25 Edited: 2010/11/27 21:43:02 
	        postfixer.h,v 1.8 2010/11/04 23:53:37 bonomi Exp  
	           Version: 1.8 Edited: 2010/11/04 23:53:37 
	        shm_subs.h,v 1.7 2010/09/16 18:27:51 bonomi Exp  
	           Version: 1.7 Edited: 2010/09/16 18:27:51 
	        shmblock.h,v 1.13 2010/11/27 21:43:02 bonomi Exp  
	           Version: 1.13 Edited: 2010/11/27 21:43:02 
              ...
              ...
 
Given such output two different versions of the same executable, and by
running a diff you know _exactly_ what modules changed, and what versions
of those modules you need to compare to see -what- is different.

This is _amazingly_ useful when chasing down 'something that _did_ work'
but now *doesn't*.

Its also D*MN useful if you ever need to reconstruct a makefile for a
particular version.

> A separation of a "kernel version file" and a "world version
> file" is useful in cases the kernel won't be touched, so no
> need to update its version file (as well as the kernel itself)
> by a binary update.
>
> The files should be easily parsable. They could even contain
> an assignment in sh syntax, as well as comments (for BSDL and
> $FreeBSD$ information). Their templates could be stored in
> the /usr/src subtree for the etc/ structure, so programs like
> "make" and "mergemaster" could access them from there.
>
> Maybe a binary command could be added to the base system to
> query this information (maybe "getent" could do that?).

See above.  
Done 'right', this stuff is already all there, with _existing- tools.

> Maybe things also present in "uname -a" output (such as architecture
> and OS name) could be included, but I think that's not required
> because it's mostly obvious. :-)

Note; things that are readily 'available elsewhere' should -not- be included
in anything.  Keep the 'official' stuff in *one* place.  let anything that
needs it consult the 'offiical' values, rather than some 'non-authoritative'
(and possibly inconsistent) copy.  If it is in uname output, anything (other
than uname, obviously) that needs it should get it _from_ uname.

> > Both kernel revision level and 'world' patchlevel are reset -only-
> > when a new minor (or major) release of the O/S is installed. Aside
> > from that, they increment semi-independantly -- 'world' patchlevel
> > is always greater-equal to kernel revision level.
> > 
> > Ideally, this is a _log_ of all the actual changes, something along the
> > lines of:
> > 
> >     BEGIN updates
> >       updated {foo}, Vers x.y.z, old file renamed to {foo}.x.y.x-replaced
> >       patchfile {foo1} for {pathname}, patch application succeeded
> >       patchfile {foo2} for {pathname}, patch application FAILED
> >       obselete file {foo3} renamed to {foo3}.x.y.z-obselete
> >     END updates   Now at patchlevel {quux}
> > 
> > For 'audit' purposes', every line is prefixed with 
> >     timestamp,
> >     login username/effective UID(as a username)
> >     the tty device from which the action was performed.
> > 
> > When a new release of the O/S is installed, the patchlog file is renamed
> > or deleted, and a single line of the form:
> > 
> >     END install   Now at patchlevel 0
> > 
> > is written.  Thus there is always an END line with the patchlevel ID.
> > 
> > The numeric patchlevel is written as a fixed-width *right-justiied* field.
> > 
> > Thus, the last 'END' starts at a 'known' position before the end of the
> > file, allowing an application to do a direct fseek(3)/lseek(2) to it (or 
> > the patchlevel) without having to read the entire file.  ('install' and
> > 'updates' are chosen with malice aforethought, they're the same length ;)
> > 
> > From the command-line, 'tail -1 {patchlog}' gets everything.
>
> Also very nice. By simply _viewing_ the file, the most non-current
> version will be discovered, so maybe (just _maybe_) re-ordering them
> in upside-down (newest version on top) would be better?

Definitely -not-.  <grin>

You obviously didn't notice that the file flags are 'sysem append only'.

The entire point of my proposal is to make it an IMMUTATABLE RECORD of
'what was done'.  'add to top' has several disadvantages.  First,
a performance issue, you do have to read down the log to find the 
first 'END' line rather than being able to seek directly to it.
Second, and the *BIG* one, you risk destroying the prior information
by re-writing the file.  Third, it makes it easier for a 'malicious'
update to cover it's tracks.

You are, I'm sure, familiar with "Murphy's Law".  (Who was, by the way,
a real person.)

Let me introduce you to, "O'Brien's Law" -- it says, very simply, and pithily,
"Murphy was an OPTIMIST!!!"

For systems work, and expecilly 'logging' it is imperative to prevent any
opportunity for O'Brien to get any handhold/traction on the situation.

'Add to top' _does_ give O'Brien some possible knobs to twist.

Until you learn to "think like O'Brien", staying ahead of him requires a
-lot- of forethought.

When you learn to design stuff that _you_ can't break -- even if you are
deliberately trying -- life gets a lot easier.  *GRIN*

> > With this kind of setup, and assuming that all distributed patchfiles have
> > 'unique' names, the 'patchlog' provides a roadmap for reconstructing the
> > state of the kernel and 'world' as of any particular point in time.
> > 
> > AT LEAST as important, it provides a record that would let one 'back out'
> > an update, to revert to a prior system state, if needed.  In fact, it
> > would be 'easy' to have automation perform that task.
>
> How about performing "version skips", e. g. from -p1 to -p4
> directly (using freebsd-update), or wider steps, e. g. from
> 8.3 to 8.4 (using sources per CVS)?

Like the Nike trademark says, "Just Do It!"  <grin>

If you do a direct update from -p1 to -p4, then when you 'unroll' the update,
you'd revert to -p1.  No way to revert directly to -p3 -- you "don't know" 
what changes were not in -p3.  To go from -p4 to -p3 in that situation, you'd
have to revert to -p1, then apply -p3.

As for an O/S minor-version (or major, for that matter) update, that is 
outside the realm of a 'patchlevel management' system.  Hopefully the version
upgrade process has its -own- provisions to (a) back up, and (b) *log*, what
is changed.  Since that version upgrade process -would- involve changing/
replacing the above-described 'patchlog', It would require a -minor- 
additional tweak to back up 'obseleted' patchlog, in addition to the tweak to
install the new 'one-line' patchlog described above..




More information about the freebsd-questions mailing list