aboutsummaryrefslogblamecommitdiff
path: root/tools/3.0-upgrade/cvt-wtmp.c
blob: c5d3b54a7bbcc5887cf8c33997cc3eaf5afa504f (plain) (tree)
























                                                                            
            






































                                                    
                                        







                                                               
                                                             





                           
                                    
 
                               
                                              

              



                    













                                 
                                     




           
                                                   





                                                                          
                       




                        
                                                               















































                                                                          























                                                                                         






                                                                      

                      









                                                                              

                      














                                                                             



















                                                                                   






























                                                                         
/*
 * Copyright (c) 1996 Joerg Wunsch
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $FreeBSD$
 *
 */

/*
 * Heuristics to convert old wtmp format to new one.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>

#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <utmp.h>


#define	OUT_NAMESIZE	8
#define	OUT_LINESIZE	8
#define	OUT_HOSTSIZE	16

struct olastlog {
	time_t	ll_time;
	char	ll_line[OUT_LINESIZE];
	char	ll_host[OUT_HOSTSIZE];
};

struct outmp {
	char	ut_line[OUT_LINESIZE];
	char	ut_name[OUT_NAMESIZE];
	char	ut_host[OUT_HOSTSIZE];
	long	ut_time;
};

void	usage(void);
void	convert(const char *, int, int);

/*
 * NB: We cannot convert lastlog yet, but we don't need either.
 */

void
usage(void)
{
  errx(EX_USAGE, "usage: cvt-wtmp [-f] [-n] /var/log/wtmp*");
}


int
main(int argc, char **argv)
{
  int errs, i, nflag, forceflag, rv;

  errs = nflag = forceflag = 0;
  while ((i = getopt(argc, argv, "fn")) != -1)
    switch (i)
      {
      case 'f':
	forceflag++;
	break;

      case 'n':
	nflag++;
	break;

      default:
	errs++;
      }
  argc -= optind;
  argv += optind;

  if (argc <= 0 || errs)
    usage();

  for (;argc > 0; argc--, argv++)
    convert(*argv, nflag, forceflag);

  return 0;
}

void
convert(const char *name, int nflag, int forceflag)
{
  struct stat sb;
  struct timeval tv[2];
  char xname[1024], yname[1024];
  unsigned char buf[128];	/* large enough to hold one wtmp record */
  int fd1, fd2;
  size_t off, shouldbe;
  int old, new;
  time_t now, early, *t;
  struct tm tm;
  struct utmp u;
  struct outmp *ou;
  enum { OLD, NEW } which = OLD; /* what we're defaulting to */

  if (stat(name, &sb) == -1)
    {
      warn("Cannot stat file \"%s\", continuing.", name);
      return;
    }

  now = time(NULL);
  /* some point in time very early, before 386BSD 0.0 */
  tm.tm_sec = 0; tm.tm_min = 0; tm.tm_hour = 0;
  tm.tm_mday = 1; tm.tm_mon = 2; tm.tm_year = 92;
  tm.tm_isdst = 0;
  early = mktime(&tm);

  tv[0].tv_sec = sb.st_atimespec.tv_sec;
  tv[0].tv_usec = sb.st_atimespec.tv_nsec / 1000;
  tv[1].tv_sec = sb.st_mtimespec.tv_sec;
  tv[1].tv_usec = sb.st_mtimespec.tv_nsec / 1000;

  /* unzipping is handled best externally */
  if (strlen(name) > 3 && memcmp(&name[strlen(name) - 3], ".gz", 3) == 0)
    {
      warnx("Cannot handle gzipped files, ignoring \"%s\".", name);
      return;
    }

  (void) snprintf(xname, sizeof xname, "%s.new", name);
  if (!nflag && (fd1 = open(xname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
    err(EX_CANTCREAT, "Can't create new wtmp file");

  if ((fd2 = open(name, O_RDONLY, 0)) == -1)
    err(EX_UNAVAILABLE, "input file magically disappeared, i'm confused");

  old = new = 0; off = 0;
  memset(buf, 0, sizeof buf);

  while (read(fd2, &buf[off], sizeof(time_t)) == sizeof(time_t))
    {
      t = (time_t *)&buf[off];
      off += sizeof(time_t);
      if (off < sizeof(struct outmp))
	/* go on */
	continue;
      if (*t < early || *t > now)
	{
	  /* unreasonable, collect another entry */
	  if (off > sizeof buf)
	    {
	      if (!forceflag)
		{
	      	  (void) unlink(xname);
		  errx(EX_UNAVAILABLE, "I can't seem to make sense out of file \"%s\",\n"
		       "Could have forced using -f.",
		     name);
		}
	      else
		{
		  warnx("Record # %d in file \"%s\" seems bogus\n"
			"(time: %d, previous time: %d, now: %d),\n"
			"continuing anyway.",
			old + new + 1, name, *t, early, now);
		  if (which == NEW)
		    {
		      (void)lseek(fd2, sizeof(struct utmp) - sizeof buf, SEEK_CUR);
		      goto write_new;
		    }
		  else
		    {
		      (void)lseek(fd2, sizeof(struct outmp) - sizeof buf, SEEK_CUR);
		      goto write_old;
		    }
		}
	    }
	  continue;
	}
      /* time is reasonable, we seem to have collected a full entry */
      if (off == sizeof(struct utmp))
	{
	  /* new wtmp record */
	  which = NEW;
	write_new:
	  new++;
	  if (!nflag)
	    {
	      if (write(fd1, buf, sizeof(struct utmp)) != sizeof(struct utmp))
		err(EX_IOERR, "writing file \"%s\"", xname);
	    }
	}
      else if (off == sizeof(struct outmp))
	{
	  /* old fart */
	  which = OLD;
	write_old:
	  old++;
	  if (!nflag)
	    {
	      ou = (struct outmp *)buf;
	      memset(&u, 0, sizeof u);
	      memcpy(&u.ut_line, ou->ut_line, OUT_LINESIZE);
	      memcpy(&u.ut_name, ou->ut_name, OUT_NAMESIZE);
	      memcpy(&u.ut_host, ou->ut_host, OUT_HOSTSIZE);
	      memcpy(&u.ut_time, &ou->ut_time, sizeof u.ut_time);
	      if (write(fd1, &u, sizeof(struct utmp)) != sizeof(struct utmp))
		err(EX_IOERR, "writing file \"%s\"", xname);
	    }
	}
      else
	{
	  if (!forceflag)
	    {
	      warnx("Illegal record in file \"%s\", ignoring.", name);
	      off = 0;
	      continue;
	    }
	  else
	    {
	      warnx("Illegal record in file \"%s\", considering it %s one.",
		    name, (which == OLD? "an old": "a new"));
	      shouldbe = (which == OLD? sizeof(struct outmp): sizeof(struct utmp));
	      if (off < shouldbe)
		(void)read(fd2, &buf[off], shouldbe - off);
	      else
		(void)lseek(fd2, shouldbe - off, SEEK_CUR);
	      if (which == OLD)
		goto write_old;
	      else
		goto write_new;
	    }
	}
      off = 0;
      /*
       * Since the wtmp file is in chronologically acsending order, we
       * can move the `early' time as we go.  Allow for one hour
       * time-of-day adjustments.
       */
      early = *t - 3600;
      memset(buf, 0, sizeof buf);
    }
  close(fd2);

  printf("File \"%s\": %d old and %d new records found.\n",
	 name, old, new);

  if (nflag)
    return;

  (void) close(fd1);
  (void) snprintf(yname, sizeof yname, "%s.bak", name);

  if (rename(name, yname) == -1)
    err(EX_OSERR, "Cannot rename \"%s\" to \"%s\"", name, yname);
  
  if (rename(xname, name) == -1)
    err(EX_OSERR, "Cannot rename \"%s\" to \"%s\"", xname, name);

  if (utimes(name, tv) == -1)
    warn("Cannot adjust access and modification times for \"%s\"", name);
}