Subject: bin/1778: testdb() in /usr/sbin/kvm_mkdb fails
To: None <gnats-bugs@gnats.netbsd.org>
From: Erik Fair <fair@quartz.clock.org>
List: netbsd-bugs
Date: 11/21/1995 01:14:01
>Number:         1778
>Category:       bin
>Synopsis:       testdb() in /usr/sbin/kvm_mkdb fails
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Nov 21 04:20:04 1995
>Last-Modified:
>Originator:     Erik Fair
>Organization:
Internet Clock Watchers
>Release:        NetBSD-current 11/18/95
>Environment:
	Sun 3/60
	NetBSD-current
System: NetBSD quartz.clock.org 1.1_ALPHA NetBSD 1.1_ALPHA (QUARTZ) #2: Mon Nov 20 16:51:57 PST 1995 fair@quartz.clock.org:/usr/src/sys/arch/sun3/compile/QUARTZ sun3


>Description:
	testdb() in /usr/sbin/kvm_mkdb fails to detect a new kernel running,
	and /usr/sbin/kvm_mkdb does not rebuild /var/db/kvm_netbsd.db
	thus do programs which use libkvm (ps, netstat, vmstat, dmesg)
	fail completely, or produce bad output.

>How-To-Repeat:
	not well understood. code examination did not reveal bug.
	bad database was nuked prior to testing (oops).

>Fix:
	work-around: rm /var/db/kvm_netbsd.db prior to running
	/usr/sbin/kvm_mkdb in /etc/rc

	a suggested fix: test st_mtime from stat(2) of database and kernel;
	rebuild database if kernel is found to be more recent. Diffs follow.


*** extern.h.orig	Mon Nov 20 23:25:31 1995
--- extern.h	Mon Nov 20 23:49:04 1995
***************
*** 36,39 ****
  
  void	create_knlist __P((char *, DB *));
  void	error __P((char *));
! int	testdb __P(());
--- 36,40 ----
  
  void	create_knlist __P((char *, DB *));
  void	error __P((char *));
! int	kvmdb_valid __P(());
! char	*Pname;
*** kvm_mkdb.c.orig	Mon Nov 20 23:24:23 1995
--- kvm_mkdb.c	Mon Nov 20 23:52:27 1995
***************
*** 76,81 ****
--- 76,83 ----
  	int ch;
  	char *p, *nlistpath, *nlistname, dbtemp[MAXPATHLEN], dbname[MAXPATHLEN];
  
+ 	Pname = ((Pname = strrchr(argv[0], '/')) ? Pname + 1 : argv[0]);
+ 
  	while ((ch = getopt(argc, argv, "")) != EOF)
  		switch (ch) {
  		case '?':
***************
*** 89,95 ****
  		usage();
  
  	/* If the existing db file matches the currently running kernel, exit */
! 	if (testdb())
  		exit(0);
  
  #define	basename(cp)	((p = rindex((cp), '/')) != NULL ? p + 1 : (cp))
--- 91,97 ----
  		usage();
  
  	/* If the existing db file matches the currently running kernel, exit */
! 	if (kvmdb_valid())
  		exit(0);
  
  #define	basename(cp)	((p = rindex((cp), '/')) != NULL ? p + 1 : (cp))
*** testdb.c.orig	Mon Nov 20 23:10:23 1995
--- testdb.c	Tue Nov 21 00:27:52 1995
***************
*** 37,43 ****
--- 37,45 ----
  #endif /* not lint */
  
  #include <sys/param.h>
+ #include <sys/types.h>
  #include <sys/file.h>
+ #include <sys/stat.h>
  #include <errno.h>
  #include <limits.h>
  #include <kvm.h>
***************
*** 49,79 ****
  
  #include "extern.h"
  
  /* Return true if the db file is valid, else false */
  int
! testdb()
  {
  	register DB *db;
  	register int cc, kd, ret, dbversionlen;
  	register char *cp, *uf;
  	DBT rec;
  	struct nlist nitem;
  	char dbname[MAXPATHLEN], dbversion[_POSIX2_LINE_MAX];
  	char kversion[_POSIX2_LINE_MAX];
  
! 	ret = 0;
  	db = NULL;
  
! 	if ((kd = open(_PATH_KMEM, O_RDONLY, 0)) < 0)
  		goto close;
  
  	uf = _PATH_UNIX;
  	if ((cp = rindex(uf, '/')) != 0)
  		uf = cp + 1;
  	(void) snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
  	if ((db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
  		goto close;
  
  	/* Read the version out of the database */
  	rec.data = VRS_KEY;
  	rec.size = sizeof(VRS_KEY) - 1;
--- 51,102 ----
  
  #include "extern.h"
  
+ #define	TRUE	1
+ #define	FALSE	0
+ 
  /* Return true if the db file is valid, else false */
  int
! kvmdb_valid()
  {
  	register DB *db;
  	register int cc, kd, ret, dbversionlen;
  	register char *cp, *uf;
  	DBT rec;
  	struct nlist nitem;
+ 	struct stat kernel_sb, db_sb;
  	char dbname[MAXPATHLEN], dbversion[_POSIX2_LINE_MAX];
  	char kversion[_POSIX2_LINE_MAX];
  
! 	ret = FALSE;
  	db = NULL;
  
! 	if ((kd = open(_PATH_KMEM, O_RDONLY, 0)) < 0) {
! 		fprintf(stderr, "%s: open(%s): %s\n", Pname, _PATH_KMEM, strerror(errno));
! 
  		goto close;
+ 	}
+ 
  
  	uf = _PATH_UNIX;
+ 	if (stat(uf, &kernel_sb) < 0) {
+ 		fprintf(stderr, "%s: stat(%s): %s\n", Pname, uf, strerror(errno));
+ 		goto close;
+ 	}
+ 
  	if ((cp = rindex(uf, '/')) != 0)
  		uf = cp + 1;
  	(void) snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
  	if ((db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
  		goto close;
  
+ 	if (stat(dbname, &db_sb) < 0) {
+ 		fprintf(stderr, "%s: stat(%s): %s\n", Pname, dbname, strerror(errno));
+ 		goto close;
+ 	}
+ 
+ 	if (kernel_sb.st_mtime > db_sb.st_mtime)
+ 		return(FALSE);
+ 
  	/* Read the version out of the database */
  	rec.data = VRS_KEY;
  	rec.size = sizeof(VRS_KEY) - 1;
***************
*** 104,110 ****
  		goto close;
  
  	/* If they match, we win */
! 	ret = bcmp(dbversion, kversion, dbversionlen) == 0;
  
  close:	if (kd >= 0)
  		(void)close(kd);
--- 127,133 ----
  		goto close;
  
  	/* If they match, we win */
! 	ret = ((bcmp(dbversion, kversion, dbversionlen) == 0) ? TRUE : FALSE);
  
  close:	if (kd >= 0)
  		(void)close(kd);
>Audit-Trail:
>Unformatted: