#!/usr/local/bin/tops -s /usr/local/tops/sys -u /opt/mytops/usr/

# Script root_time for tops
{
   This file sets the machine's date and time using the time correction
   from tops obtained from a recent connection to the Internet.

   Run by root, the words below reset the machine's date and time to 
   be consistent, within about one second, with time determined pre-
   viously by tops that accounts for the error in machine time.

   Machine clocks generally keep poor time, perhaps changing by five or
   more seconds per day.  If tops is connected to the Internet fairly 
   often, and word NISTdelta is used to get a corrected time, then the 
   saved time correction that this script uses is probably accurate.

   How tops gets the corrected time:

      When connected to the Internet, word NISTdelta is run to get 
      date and time from the National Institute of Standards and 
      Technology.  After the time is obtained, word NISTdelta runs 
      word GMTdelta to set the correction between the machine's time 
      and top's time.  

      As an example, word pppconnect (web.v) runs word NISTdelta to
      determine the time correction whenever a dial-up connection is 
      made.

   How tops remembers the corrected time:

      Functions can be placed in word uclean (sys/uboot.v), a user 
      function called by tops on exit.  Word params_put has been placed
      into uclean to save in file usr/.params.bin the information neces-
      sary to correct the machine's time.  

      User functions can also be called on start up.  For next start 
      up, word params_get has been placed in sys/uboot.v to read the 
      saved information and correct the time in tops.

   Using this file:

      One use of this file is to run it while root shuts down the 
      machine, to reset the clock closer to the correct time.  

      The file will run tops and obtain the saved time correction.  It
      is used to change the machine's date and time, and no Internet 
      connection is made.

      Here is an alias for doing this, called "off," in root's .bashrc 
      file:

         alias off='root_time; sleep 2; /sbin/shutdown -h now'

      The sleep period gives new file usr/.params.bin written on exit 
      from this script--now with zero time correction--a moment to 
      settle in before shutdown. 
}
\-----------------------------------------------------------------------
{  
   This script runs the Unix date command through word shell.  It is
   basically an exercise in time and date functions; setting the clock
   would be much easier if function settimeofday() were in the program.

   Time, date and calendar functions used are:
      time, time1, date, sysdate, greg, gdate

   The Unix date command takes a specification of time only to the 
   nearest second.

   For the desired time correction, this script creates the date com-
   mand string for the minute starting after the current one, and then
   idles until that minute begins before running the date command.

   Using calendar words, this script should work correctly any time, 
   even on Dec 31 at 23:59.

   NOTE: ROOT'S usrpath MUST CONTAIN A FILE uboot.v THAT SOURCES
   WORDS params_get and params_put.  DO NOT RUN THIS SCRIPT IN A
   DIRECTORY CONTAINING DEFAULT uboot.v THAT DOES NOT SOURCE WORDS
   params_get and params_put.
}
   getuid 0<> IF " must be root" . nl halt THEN
   
   "params_get" exists? not
   IF "root_time: word params_get is missing; halting" . nl HALT 
   THEN

\  On start up, this script has acquired the GMT delta correction
\  by running params_get in start up file sys/uboot.v.  Word time
\  will reflect the correction, while word time1 gives the machine's
\  time without the correction:

   time time1 less abs 1 <
   IF "Machine time error is less than one second" . nl exit THEN

   "Root setting machine time to remove" . 
   time time1 less .i " second error:" . nl

\  Using tops date that utilizes the saved Internet time correction:
      date (qDate) sysdate (YYYMMDD HHmmSS)

\  The Unix date command receives time only to the nearest minute.  

\  To set time to the nearest second, figure when the next minute 
\  starts and idle until then before setting the date:

      (HHmmSS) 100 /mod swap (HHmm SS) 

      60 swap (SS) less (n) \ seconds until the next minute begins

      " idle" . dup (n) .i " seconds until next minute begins ..." .

      (n) idle   \ idle until the current minute is up
      " done" . nl 

      (HHmm) tic \ tic the time to this next minute

      (HHmm) this 100 mod (mm) 59 > \ adjust if mm rolled over
      IF 100 /mod tic this 23 > 
         IF 2drop 2400
         ELSE 100 * lop
         THEN
         (YYYMMDD HHmm) this 2359 >  \ adjust if HH rolled over
         IF (YYYMMDD HHmm) drop      \ bump DD to next day
            no catmsg 
            "cal.v" filefound drop source \ get the calendar troops
            (YYYMMDD) greg tic (g) gdate 0000 (YYYMMDD 0000)
         THEN
      THEN

\  Making the string for the Unix date command.

\  The string for the Unix date command is of the form:
\        MMDDHHmmYY, as for March 5, 2003 at 8:09: 0305080903

      (YYYMMDD HHmm)

      (HHmm) int "%04d" format (qHHmm) swap 
      (YYYMMDD) 10000 /mod this 99 > IF 100 - THEN (YY)
      (YY) int "%02d" format (qYY) swap
      (MMDD) int "%04d" format (qMMDD)
      (qHHmm qYY qMMDD)
      rot cat swap cat (qMMDDHHmmYY) 

   "date " swap cat shell       \ root setting machine date and time
   0 GMTdelta                   \ zero the machine's error
   yes "params_put" "ROOT" bank \ allow root to update file on exit
   exit                         \ new usr/.params.bin will be written

{

How to use this file when shutting down the machine.

1. Copy this C program to /etc/ppp/off.c, then compile and set permissions
as described.  The compiled program will allow any user, not just root,
to shut down the machine:

/* off.c
   Adapted from pppoff.c (which is contained in file tops/sys/pppcon.v).

   The program created by this file allows non-root to shut down the 
   machine using the command off.

   While logged in as root compile and set permissions:
      gcc -o off off.c
      chmod a+x off
      chmod +s off
*/
#include <signal.h>
#include <sys/param.h>
#include <pwd.h>
static char *trusted_env[]={"PATH=/usr/bin:/usr/sbin:/sbin:/bin",0};
main()
{
        struct passwd *pwd;
                int i;
                        uid_t uid;
                        for (i=0;i < NSIG;i++){ if(i!= SIGKILL && i!=SIGCHLD)
                                                                {(void) signal(i,SIG_IGN);}
                                                                                    }
                        uid=getuid();

                        if ( (pwd = getpwuid(uid))== (struct passwd *)0 )
                                    exit(1);
                        setuid((uid_t)0);

                        execle("/etc/ppp/off_script","/etc/ppp/off_script",(char *)0,trusted_env);

                        setuid(uid);
                        exit(1);
}


2. Optionally add a link to program off in /usr/local/bin:
[root@riggo] /usr/local/bin # ll
total 3
drwxr-xr-x  3 root root 1024 Nov  4 17:37 ./
drwxr-xr-x 17 root root 1024 Nov  2 14:51 ../
lrwxrwxrwx  1 root root   12 Nov  4 17:37 off -> /etc/ppp/off*
lrwxrwxrwx  1 root root   15 Nov  2  2003 pppoff -> /etc/ppp/pppoff*
lrwxrwxrwx  1 root root   23 Dec 30  2004 tops -> /opt/tops/tops/src/tops*
drwxrwxr-x  2 root root          1024 Nov  2  2003 voice/
[root@riggo] /usr/local/bin # 


3. Copy the following script to /etc/ppp/off_script; this is the script
that is run by program off compiled in step 1:

#!/bin/sh
/usr/local/tops/usr/root_time
sleep 2
/sbin/shutdown -h now


4. Here are the files in /etc/ppp:
[root@riggo] /etc/ppp # ll off*
-rwsr-sr-x    1 root  root     14220 Nov  4 17:17 off*
-rw-rw-r--    1 dale  dale       798 Nov  4 17:16 off.c
-rwxr-xr-x    1 root  root        72 Nov  4 17:15 off_script*
[root@riggo] /etc/ppp # 


5. Users need /etc/ppp on their paths, or /usr/local/bin if the link in
step 2 is created.

}
