--- a
+++ b/busyelks/be1/clock.c
@@ -0,0 +1,430 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+
+
+/* V1.0
+ * CMOS clock manipulation - Charles Hedrick, hedrick@cs.rutgers.edu, Apr 1992
+ * 
+ * clock [-u] -r  - read cmos clock
+ * clock [-u] -w  - write cmos clock from system time
+ * clock [-u] -s  - set system time from cmos clock
+ * clock [-u] -a  - set system time from cmos clock, adjust the time to
+ *                  correct for systematic error, and put it back to the cmos.
+ *  -u indicates cmos clock is kept in universal time
+ *
+ * The program is designed to run setuid, since we need to be able to
+ * write the CMOS port.
+ *
+ * I don't know what the CMOS clock will do in 2000, so this program
+ * probably won't work past the century boundary.
+ *
+ *********************
+ * V1.1
+ * Modified for clock adjustments - Rob Hooft, hooft@chem.ruu.nl, Nov 1992
+ * Also moved error messages to stderr. The program now uses getopt.
+ * Changed some exit codes. Made 'gcc 2.3 -Wall' happy.
+ *
+ * I think a small explanation of the adjustment routine should be given
+ * here. The problem with my machine is that its CMOS clock is 10 seconds 
+ * per day slow. With this version of clock.c, and my '/etc/rc.local' 
+ * reading '/etc/clock -au' instead of '/etc/clock -u -s', this error 
+ * is automatically corrected at every boot. 
+ *
+ * To do this job, the program reads and writes the file '/etc/adjtime' 
+ * to determine the correction, and to save its data. In this file are 
+ * three numbers: 
+ *
+ * 1) the correction in seconds per day (So if your clock runs 5 
+ *    seconds per day fast, the first number should read -5.0)
+ * 2) the number of seconds since 1/1/1970 the last time the program was
+ *    used.
+ * 3) the remaining part of a second which was leftover after the last 
+ *    adjustment
+ *
+ * Installation and use of this program:
+ *
+ * a) create a file '/etc/adjtime' containing as the first and only line:
+ *    '0.0 0 0.0'
+ * b) run 'clock -au' or 'clock -a', depending on whether your cmos is in
+ *    universal or local time. This updates the second number.
+ * c) set your system time using the 'date' command.
+ * d) update your cmos time using 'clock -wu' or 'clock -w'
+ * e) replace the first number in /etc/adjtime by your correction.
+ * f) put the command 'clock -au' or 'clock -a' in your '/etc/rc.local'
+ *
+ * If the adjustment doesn't work for you, try contacting me by E-mail.
+ *
+ ******
+ * V1.2
+ *
+ * Applied patches by Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de)
+ * Patched and indented by Rob Hooft (hooft@EMBL-Heidelberg.DE)
+ * 
+ * A free quote from a MAIL-message (with spelling corrections):
+ *
+ * "I found the explanation and solution for the CMOS reading 0xff problem
+ *  in the 0.99pl13c (ALPHA) kernel: the RTC goes offline for a small amount
+ *  of time for updating. Solution is included in the kernel source 
+ *  (linux/kernel/time.c)."
+ *
+ * "I modified clock.c to fix this problem and added an option (now default,
+ *  look for USE_INLINE_ASM_IO) that I/O instructions are used as inline
+ *  code and not via /dev/port (still possible via #undef ...)."
+ *
+ * With the new code, which is partially taken from the kernel sources, 
+ * the CMOS clock handling looks much more "official".
+ * Thanks Harald (and Torsten for the kernel code)!
+ *
+ ******
+ * V1.3
+ * Canges from alan@spri.levels.unisa.edu.au (Alan Modra):
+ * a) Fix a few typos in comments and remove reference to making
+ *    clock -u a cron job.  The kernel adjusts cmos time every 11
+ *    minutes - see kernel/sched.c and kernel/time.c set_rtc_mmss().
+ *    This means we should really have a cron job updating
+ *    /etc/adjtime every 11 mins (set last_time to the current time
+ *    and not_adjusted to ???).
+ * b) Swapped arguments of outb() to agree with asm/io.h macro of the
+ *    same name.  Use outb() from asm/io.h as it's slightly better.
+ * c) Changed CMOS_READ and CMOS_WRITE to inline functions.  Inserted
+ *    cli()..sti() pairs in appropriate places to prevent possible
+ *    errors, and changed ioperm() call to iopl() to allow cli.
+ * d) Moved some variables around to localise them a bit.
+ * e) Fixed bug with clock -ua or clock -us that cleared environment
+ *    variable TZ.  This fix also cured the annoying display of bogus
+ *    day of week on a number of machines. (Use mktime(), ctime()
+ *    rather than asctime() )
+ * f) Use settimeofday() rather than stime().  This one is important
+ *    as it sets the kernel's timezone offset, which is returned by
+ *    gettimeofday(), and used for display of MSDOS and OS2 file
+ *    times.
+ * g) faith@cs.unc.edu added -D flag for debugging
+ *
+ * V1.4: alan@SPRI.Levels.UniSA.Edu.Au (Alan Modra)
+ *       Wed Feb  8 12:29:08 1995, fix for years > 2000.
+ *       faith@cs.unc.edu added -v option to print version.
+ *
+ ******
+ * V1.4.ELKS
+ *
+ * Converted by Shane Kerr <kerr@wizard.net>, 1998-01-03
+ * 
+ * Removed the adjustment option, because it used floating
+ * point math, and because I don't use it.  If necessary,
+ * it can certainly be added back in.
+ * 
+ * Deleted the commented out options for debug code, because
+ * they were cluttering up this already cluttered source file.
+ *
+ * Switched from using mktime(), with the associated time zone
+ * baggage, to the hand-crafted utc_mktime(), getting time
+ * zone information from gettimeofday() rather than the 
+ * environment variables.
+ *
+ * Removed the code to set the timezone with settimeofday.
+ * This should probably be added back in at some point...
+ *
+ * I had to remove the code that waits for the falling edge
+ * of the update flag -- it never seems to actually happen!
+ * And since the long code is so slow, the program just locks.
+ */
+
+#define VERSION "1.4.ELKS"
+
+/* Globals */
+int readit = 0;
+int writeit = 0;
+int setit = 0;
+int universal = 0;
+
+void clock_usage()
+{
+    fprintf(stderr, "clock [-u] -r|w|s|v\n");
+    fprintf(stderr, "  r: read and print CMOS clock\n");
+    fprintf(stderr, "  w: write CMOS clock from system time\n");
+    fprintf(stderr, "  s: set system time from CMOS clock\n");
+    fprintf(stderr, "  u: CMOS clock is in universal time\n");
+    fprintf(stderr, "  v: print version (%s) and exit\n", VERSION);
+    exit(1);
+}
+
+#asm
+_inb:
+    push bp
+    mov bp, sp
+    push dx
+    xor ax, ax
+    mov dx, 4[bp]
+    in al, dx
+    pop dx
+    pop bp
+    ret
+#endasm
+
+#asm
+_outb:
+    push bp
+    mov bp, sp
+    push ax
+    push dx
+    xor ax, ax
+    mov al, 4[bp]
+    mov dx, 6[bp]
+    out dx, al
+    pop dx
+    pop ax
+    pop bp
+    ret
+#endasm
+
+unsigned char cmos_read(reg)
+unsigned char reg;
+{
+  register unsigned char ret;
+#asm
+  cli
+#endasm
+  outb (reg | 0x80, 0x70);
+  ret = inb (0x71);
+#asm
+  sti
+#endasm
+  return ret;
+}
+
+void cmos_write(reg, val)
+unsigned char reg;
+unsigned char val;
+{
+  outb (reg | 0x80, 0x70);
+  outb (val, 0x71);
+}
+
+
+int cmos_read_bcd (addr)
+int addr;
+{
+  int b;
+  b = cmos_read (addr);
+  return (b & 15) + (b >> 4) * 10;
+}
+
+void cmos_write_bcd (addr, value)
+int addr; 
+int value;
+{
+  cmos_write (addr, ((value / 10) << 4) + value % 10);
+}
+
+int clock_main (argc, argv)
+int argc;
+char **argv;
+{
+  struct tm tm;
+  time_t systime;
+  time_t last_time;
+  int arg;
+  double factor;
+  double not_adjusted;
+  unsigned char save_control, save_freq_select;
+
+  while ((arg = getopt (argc, argv, "rwsuaDv")) != -1)
+    {
+      switch (arg)
+	{
+	case 'r':
+	  readit = 1;
+	  break;
+	case 'w':
+	  writeit = 1;
+	  break;
+	case 's':
+	  setit = 1;
+	  break;
+	case 'u':
+	  universal = 1;
+	  break;
+	case 'v':
+	  fprintf(stderr, "clock %s\n", VERSION);
+	  exit(0);
+	default:
+	  usage ();
+	}
+    }
+
+  if (readit + writeit + setit > 1)
+    usage ();			/* only allow one of these */
+
+  if (!(readit | writeit | setit ))	/* default to read */
+    readit = 1;
+
+  if (readit || setit)
+    {
+#if 0
+      long i;
+
+/* read RTC exactly on falling edge of update flag */
+/* Wait for rise.... (may take upto 1 second) */
+
+      for (i = 0; i < 10000000L; i++)	
+	if (cmos_read (10) & 0x80)
+	  break;
+
+/* Wait for fall.... (must try at least 2.228 ms) */
+
+      for (i = 0; i < 1000000L; i++)	
+	if (!(cmos_read (10) & 0x80))
+	  break;
+#endif /* 0 */
+
+/* The purpose of the "do" loop is called "low-risk programming" */
+/* In theory it should never run more than once */
+      do
+	{ 
+	  tm.tm_sec = cmos_read_bcd (0);
+	  tm.tm_min = cmos_read_bcd (2);
+	  tm.tm_hour = cmos_read_bcd (4);
+	  tm.tm_wday = cmos_read_bcd (6);
+	  tm.tm_mday = cmos_read_bcd (7);
+	  tm.tm_mon = cmos_read_bcd (8);
+	  tm.tm_year = cmos_read_bcd (9);
+	}
+      while (tm.tm_sec != cmos_read_bcd (0));
+      if (tm.tm_year < 70)
+	    tm.tm_year += 100;  /* 70..99 => 1970..1999, 0..69 => 2000..2069 */
+      tm.tm_mon--;		/* DOS uses 1 base */
+      tm.tm_wday -= 3;		/* DOS uses 3 - 9 for week days */
+      tm.tm_isdst = -1;		/* don't know whether it's daylight */
+    }
+
+  if (readit || setit)
+    {
+/* 
+ * utc_mktime() assumes we're in Greenwich, England.  If the CMOS 
+ * clock isn't in GMT, we need to adjust.  We'll just use the
+ * time zone information returned in gettimeofday().
+ */
+      systime = utc_mktime(&tm);
+      if (!universal) {
+          struct timezone tz;
+          
+          gettimeofday(NULL, &tz);
+          systime += tz.tz_minuteswest * 60L;
+      }
+#if 0
+/*
+ * mktime() assumes we're giving it local time.  If the CMOS clock
+ * is in GMT, we have to set up TZ so mktime knows it.  tzset() gets
+ * called implicitly by the time code, but only the first time.  When
+ * changing the environment variable, better call tzset() explicitly.
+ */
+      if (universal)
+	{
+	  char *zone;
+	  zone = (char *) getenv ("TZ");	/* save original time zone */
+	  (void) putenv ("TZ=");
+	  tzset ();
+	  systime = mktime (&tm);
+	  /* now put back the original zone */
+	  if (zone)
+	    {
+
+             char *zonebuf;
+             zonebuf = malloc (strlen (zone) + 4);
+             strcpy (zonebuf, "TZ=");
+             strcpy (zonebuf+3, zone);
+             putenv (zonebuf);
+             free (zonebuf);
+	    }
+	  else
+	    {			/* wasn't one, so clear it */
+	      putenv ("TZ");
+	    }
+	  tzset ();
+	}
+      else
+	{
+	  systime = mktime (&tm);
+	}
+#endif /* 0 */
+    }
+
+  if (readit)
+    {
+      printf ("%s", ctime (&systime ));
+    }
+
+  if (setit)
+    {
+      struct timeval tv;
+      struct timezone tz;
+
+/* program is designed to run setuid, be secure! */
+
+      if (getuid () != 0)
+	{			
+	  fprintf (stderr, "Sorry, must be root to set time\n");
+	  exit (2);
+	}
+
+#ifndef KEEP_OFF
+      tv.tv_sec = systime;
+      tv.tv_usec = 0;
+#if 0
+      tz.tz_minuteswest = timezone / 60;
+      tz.tz_dsttime = daylight;
+
+      if (settimeofday (&tv, &tz) != 0)
+#else
+      if (settimeofday (&tv, NULL) != 0)
+#endif
+        {
+	  fprintf (stderr,
+		   "Unable to set time -- probably you are not root\n");
+	  exit (1);
+	}
+      
+#endif
+    }
+  
+  if (writeit)
+    {
+      struct tm *tmp;
+      systime = time (NULL);
+      if (universal)
+	tmp = gmtime (&systime);
+      else
+	tmp = localtime (&systime);
+
+#ifndef KEEP_OFF
+#asm
+      cli
+#endasm
+      save_control = cmos_read (11);   /* tell the clock it's being set */
+      cmos_write (11, (save_control | 0x80));
+      save_freq_select = cmos_read (10);       /* stop and reset prescaler */
+      cmos_write (10, (save_freq_select | 0x70));
+
+      cmos_write_bcd (0, tmp->tm_sec);
+      cmos_write_bcd (2, tmp->tm_min);
+      cmos_write_bcd (4, tmp->tm_hour);
+      cmos_write_bcd (6, tmp->tm_wday + 3);
+      cmos_write_bcd (7, tmp->tm_mday);
+      cmos_write_bcd (8, tmp->tm_mon + 1);
+      cmos_write_bcd (9, tmp->tm_year);
+
+      cmos_write (10, save_freq_select);
+      cmos_write (11, save_control);
+#asm
+      sti
+#endasm
+#endif
+    }
+  exit (0);
+}