[net.sources] new setdate

fnf@unisoft.UUCP (Fred Fish) (02/28/85)

Here is a new distribution of setdate (many people on BSD systems
complained about a missing liby.a).  It turns out the only thing
needed was yyerror().

Don't forget to define OLDFORMAT when appropriate (you get a
"bad conversion" message from "date" otherwise).

-Fred

#--------CUT---------CUT---------CUT---------CUT--------#
#########################################################
#                                                       #
# This is a shell archive file.  To extract files:      #
#                                                       #
#    1)	Make a directory for the files.                 #
#    2) Write a file, such as "file.shar", containing   #
#       this archive file into the directory.           #
#    3) Type "sh file.shar".  Do not use csh.           #
#                                                       #
#########################################################
#
#
echo Extracting Makefile:
sed 's/^Z//' >Makefile <<\STUNKYFLUFF
Z#
Z#  FILE
Z#
Z#	Makefile
Z#
Z#  SCCS
Z#
Z#	@(#)Makefile	1.3	2/27/85
Z#
Z#  DESCRIPTION
Z#
Z#	Makefile for the system boot utility "setdate" which
Z#	sets the current date and time.  Accepts a wide variety
Z#	of date formats.
Z#
Z#  AUTHOR
Z#
Z#	Fred Fish
Z#	(Currently at UniSoft Systems Inc.)
Z#
Z
Z.l~.c:
Z	$(GET) $(GFLAGS) -p $< >$*.l
Z	$(LEX) $(LFLAGS) $*.l
Z	mv lex.yy.c $*.c
Z	rm -f $*.l
Z
Z.y~.y:
Z	$(GET) $(GFLAGS) -p $< >$*.y
Z
Zsetdate :	setdate.o
Z		$(CC) -o $@ $?
Z
Zsetdate.o :	setdate.c lex.c
Z
Zsetdate.c :	setdate.y
Z
Z#
Z#	Clean up the directory.
Z#
Z
Zclean :
Z		rm -f *.BAK *.o
Z
Zclobber :
Z		rm -f setdate.c lex.c setdate
Z
Z
STUNKYFLUFF
set `sum Makefile`
if test 40062 != $1
then
echo Makefile: Checksum error. Is: $1, should be: 40062.
fi
#
#
echo Extracting lex.l:
sed 's/^Z//' >lex.l <<\STUNKYFLUFF
Z%{
Z/************************************************************************
Z *									*
Z *			Copyright (c) 1985, Fred Fish			*
Z *			    All Rights Reserved				*
Z *									*
Z *	This software and/or documentation is released into the		*
Z *	public domain for personal, non-commercial use only.		*
Z *	Limited rights to use, modify, and redistribute are hereby	*
Z *	granted for non-commercial purposes, provided that all		*
Z *	copyright notices remain intact and all changes are clearly	*
Z *	documented.  The author makes no warranty of any kind with	*
Z *	respect to this product and explicitly disclaims any implied	*
Z *	warranties of merchantability or fitness for any particular	*
Z *	purpose.							*
Z *									*
Z ************************************************************************
Z */
Z
Z
Z/*
Z *  FILE
Z *
Z *	lex.l
Z *
Z *  SCCS
Z *
Z *	@(#)lex.l	1.2	2/10/85
Z *
Z *  DESCRIPTION
Z *
Z *	Lex code for setdate utility.  This must be processed by the
Z *	UNIX "lex" utility to produce a lexical analyzer.
Z *
Z *	Note that month names and other such strings are recognized
Z *	case independently.
Z *
Z *	The values returned for month names are in the range [1-12]
Z *	for the months [Jan-Dec] respectively.
Z *
Z *  AUTHOR
Z *
Z *	Fred Fish
Z *	(Currently at UniSoft Systems Inc.)
Z *
Z */
Z%}
Z
Z%%
Z
Z(P|p)(M|m)	{
Z			return (PM); 
Z		}
Z
Z(A|a)(M|m)	{
Z			return (AM); 
Z		}
Z
Z[0-9]+		{
Z			yylval = atoi(yytext);
Z			return(DIGITS);
Z		}
Z
Z((J|j)(A|a)(N|n))((U|u)(A|a)(R|r)(Y|y))? {
Z			yylval = 1; 
Z			return (MONTH);
Z		}
Z
Z((F|f)(E|e)(B|b))((R|r)(U|u)(A|a)(R|r)(Y|y))? {
Z			yylval = 2; 
Z			return (MONTH);
Z		}
Z
Z((M|m)(A|a)(R|r))((C|c)(H|h))? {
Z			yylval = 3; 
Z	 		return (MONTH);
Z		}
Z
Z((A|a)(P|p)(R|r))((I|i)(L|l))? {
Z			yylval = 4; 
Z			return (MONTH);
Z		}
Z
Z(M|m)(A|a)(Y|y) {
Z			yylval = 5;
Z			return(MONTH);
Z		}
Z
Z((J|j)(U|u)(N|n))((E|e))? {
Z			yylval = 6;
Z			return(MONTH);
Z		}
Z
Z((J|j)(U|u)(L|l))((Y|y))? {
Z			yylval = 7;
Z			return(MONTH);
Z		}
Z
Z((A|a)(U|u)(G|g))((U|u)(S|s)(T|t))? {
Z			yylval = 8;
Z			return(MONTH);
Z		}
Z
Z((S|s)(E|e)(P|p))((T|t)(E|e)(M|m)(B|b)(E|e)(R|r))? {
Z			yylval = 9;
Z			return(MONTH);
Z		}
Z
Z((O|o)(C|c)(T|t))((O|o)(B|b)(E|e)(R|r))? {
Z			yylval = 10;
Z			return(MONTH);
Z		}
Z
Z((N|n)(O|o)(V|v))((E|e)(M|m)(B|b)(E|e)(R|r))? {
Z			yylval = 11;
Z			return(MONTH);
Z		}
Z
Z((D|d)(E|e)(C|c))((E|e)(M|m)(B|b)(E|e)(R|r))? {
Z			yylval = 12;
Z			return(MONTH);
Z		}
Z
Z","		{
Z			return(COMMA);
Z		}
Z
Z"/"		{
Z			return(SLASH);
Z		}
Z
Z"-"		{
Z			return(DASH);
Z	      	}
Z
Z":"		{
Z			return(COLON);
Z		}
Z
Z[ \t]		{;}
Z
Z[\n]		{
Z			return(-1);
Z		}
Z%%
Z
STUNKYFLUFF
set `sum lex.l`
if test 41284 != $1
then
echo lex.l: Checksum error. Is: $1, should be: 41284.
fi
#
#
echo Extracting setdate.y:
sed 's/^Z//' >setdate.y <<\STUNKYFLUFF
Z/************************************************************************
Z *									*
Z *			Copyright (c) 1985, Fred Fish			*
Z *			    All Rights Reserved				*
Z *									*
Z *	This software and/or documentation is released into the		*
Z *	public domain for personal, non-commercial use only.		*
Z *	Limited rights to use, modify, and redistribute are hereby	*
Z *	granted for non-commercial purposes, provided that all		*
Z *	copyright notices remain intact and all changes are clearly	*
Z *	documented.  The author makes no warranty of any kind with	*
Z *	respect to this product and explicitly disclaims any implied	*
Z *	warranties of merchantability or fitness for any particular	*
Z *	purpose.							*
Z *									*
Z ************************************************************************
Z */
Z
Z
Z/*
Z *  FILE
Z *
Z *	setdate.y
Z *
Z *  SCCS
Z *
Z *	@(#)setdate.y	1.2	2/27/85
Z *
Z *  DESCRIPTION
Z *
Z *	YACC grammar for a system bootup time/date set utility.
Z *
Z *	Accepts date and time in several common formats, for
Z *	example:
Z *
Z *		January 18,1983  18:45
Z *		Jan 18, 1983 18:45:00
Z *		Jan 18, 1983 6:45 PM
Z *		18:43  18-Jan-83
Z *		01/18/83
Z *		18:43
Z *		8 AM
Z *
Z *  AUTHOR
Z *
Z *	Fred Fish
Z *	(Currently at UniSoft Systems Inc.)
Z *
Z */
Z
Z%{
Z#include <stdio.h>
Z#include <time.h>
Z
Z#define SYS_ERROR (-1)		/* Returned by system calls on error */
Z#define FALSE (0)		/* Boolean false */
Z#define TRUE (1)		/* Boolean true */
Z
Zstatic struct tm *newtime;	/* Time to set current time to */
Zstatic int morning = FALSE;	/* Explicit morning specified */
Zstatic int evening = FALSE;	/* Explicit evening specified */
Z
Zextern long time ();		/* Get current clock value */
Zextern struct tm *localtime ();	/* Get local time from clock value */
Zextern char *asctime ();	/* Convert local time to string form */
Z
Z%}
Z
Z%token DIGITS MONTH SLASH DASH COMMA COLON AM PM
Z
Z%%
Z
Zwhen	:	date
Z	|	time
Z	|	date time
Z	|	time date
Z	|	/* empty */
Z	;
Z
Zdate	:	DIGITS SLASH DIGITS SLASH DIGITS
Z			{
Z				newtime -> tm_mon = $1 - 1;
Z				newtime -> tm_mday = $3;
Z				newtime -> tm_year = $5 % 100;
Z			}
Z	|	DIGITS DASH MONTH DASH DIGITS
Z			{
Z				newtime -> tm_mday = $1;
Z				newtime -> tm_mon = $3 - 1;
Z				newtime -> tm_year = $5 % 100;
Z			}
Z	|	MONTH DIGITS COMMA DIGITS
Z			{
Z				newtime -> tm_mon = $1 - 1;
Z				newtime -> tm_mday = $2;
Z				newtime -> tm_year = $4 % 100;
Z			} 
Z	|	MONTH DIGITS
Z			{
Z				newtime -> tm_mon = $1 - 1;
Z				newtime -> tm_mday = $2;
Z			} 
Z	;
Z
Ztime	:	clock
Z	|	clock period
Z	;
Z
Zclock	:	DIGITS COLON DIGITS COLON DIGITS
Z			{
Z				newtime -> tm_hour = $1;
Z				newtime -> tm_min = $3;
Z				newtime -> tm_sec = $5;
Z			}
Z	|	DIGITS COLON DIGITS 
Z			{
Z				newtime -> tm_hour = $1;
Z				newtime -> tm_min = $3;
Z				newtime -> tm_sec = 0;
Z			}
Z	|	DIGITS
Z			{
Z				newtime -> tm_hour = $1;
Z				newtime -> tm_min = 0;
Z				newtime -> tm_sec = 0;
Z			}
Z	;
Z
Zperiod	:	AM
Z			{
Z			    	morning = TRUE;
Z			}
Z	|	PM
Z			{
Z				evening = TRUE;
Z			}
Z	;
Z	
Z%%
Z
Zint main (argc, argv)
Zint argc;
Zchar *argv[];
Z{
Z    char buffer[64];		/* buffer to hold arg for date util */
Z    register char ch;		/* peek at first character of input */
Z    register int status;	/* system call result code */
Z    auto long systime;		/* Current system time */
Z
Z    if (time (&systime) == SYS_ERROR) {
Z	fprintf (stderr, "%s: can't get current time: ", argv[0]);
Z	perror ("");
Z    }
Z    newtime = localtime (&systime);
Z    do {
Z	printf ("Enter current date & time (? for help) >> ");
Z	fflush (stdout);
Z	ch = getchar ();				/* Peek at first */
Z	if (ch == '?') {				/* Wants help? */
Z	    usage ();					/* Give good help */
Z	    while (getchar () != '\n') {;}		/* Flush line */
Z	} else {
Z	    ungetc (ch, stdin);				/* Put back peek */
Z	}
Z    } while (ch == '?');				/* Until no ? */
Z    yyparse ();
Z    if (morning) {
Z	newtime -> tm_hour %= 12;
Z    } else if (evening) {
Z	newtime -> tm_hour %= 12;
Z	newtime -> tm_hour += 12;
Z    }
Z#ifdef OLDFORMAT
Z    sprintf (buffer,"date %02.2d%02.2d%02.2d%02.2d%02.2d.%02.2d",
Z	newtime -> tm_year,
Z	newtime -> tm_mon + 1,
Z	newtime -> tm_mday,
Z	newtime -> tm_hour,
Z	newtime -> tm_min,
Z	newtime -> tm_sec);
Z#else
Z    sprintf (buffer,"date %02.2d%02.2d%02.2d%02.2d%02.2d",
Z	newtime -> tm_mon + 1,
Z	newtime -> tm_mday,
Z	newtime -> tm_hour,
Z	newtime -> tm_min,
Z	newtime -> tm_year);
Z#endif
Z    status = system (buffer);
Z    if (status == SYS_ERROR) {
Z	fprintf (stderr, "%s: can't set time: ", argv[0]);
Z	perror ("");
Z    }
Z    return (status);
Z}
Z
Zstatic char *documentation[] = {
Z    "",
Z    "Date and time may be entered in any of several common formats.",
Z    "Default is current date and time.  Examples are:",
Z    "",
Z    "\tApril 14, 1983  13:41",
Z    "\t14-Apr-83  13:41:00",
Z    "\t4/14/83  13:41",
Z    "\t1:41 PM",
Z    "\tApr 14",
Z    "",
Z    "Acceptable but not recommended are:",
Z    "",
Z    "\tApr 14, 83",
Z    "\t14-April-1983",
Z    "\t4/14/1983",
Z    "",
Z    0,					/* MARKS END OF STRING LIST */
Z};
Z
Zstatic usage()
Z{
Z    register char **dp;
Z
Z    dp = documentation;			/* Init string pointer pointer */
Z    while (*dp) {			/* While another good pointer */
Z	printf ("%s\n", *dp++);		/* Print what it points to */
Z    }
Z}
Z
Zyywrap ()				/* Thought this was in library */
Z{
Z    return (1);
Z}
Z
Zyyerror (s)				/* Provide default error handling */
Zchar *s;
Z{
Z    fprintf (stderr, "%s\n", s);
Z}
Z
Z#include "lex.c"			/* Output of "lex" from lex.l */
Z
STUNKYFLUFF
set `sum setdate.y`
if test 42629 != $1
then
echo setdate.y: Checksum error. Is: $1, should be: 42629.
fi
echo ALL DONE BUNKY!
exit 0

root@bu-cs.UUCP (Barry Shein) (03/04/85)

This made me think of something we use here that I wrote.
It is only useful to those running TCP/IP (4.2bsd) although I
suppose it could be adapted to some other net.
Look at it a bit before relying on it, it is very simple:

Rdate just execs itself on a remote system to generate a
string which, when passed to system() will set the local time.
Some will consider this too naive to be relied on as a
remote time-server which is technically true but it is
going to be more accurate than just looking at your watch.
By accurate I mean: Will bring two systems into very close time
which may or may not be the correct time.

--------------------CUT HERE: /usr/man/man8/rdate.8--------------------
.TH RDATE 8L "20 Aug 1984"
.UC 4
.SH NAME
rdate \- remote date and time service
.SH SYNOPSIS
.B rdate
[
.B \-h
host
] [
.B \-u
user
] [
.B \-p
passwd
] [
.B \-s
] [
.B \-t
]
.SH DESCRIPTION
.I Rdate
sets the system's date and time by querying
another system over the network.
.PP
The
.I host
should default to a reasonable value or can be
overridden with the
.B \-h
flag followed by the host name. Obviously this other
host must also have this service.
.PP
You must be logged in as the super-user in order to
set the date on the current system. Unfortunately,
you must not be logged in as the super-user in order
to access the remote system (these are both intentional
features.)
.PP
To get around this you must specify
a non-privileged user name and password for
an account on the remote machine. This can
be done either on the command line via the
.B \-u
and
.B \-p
commands for
.I user
and
.I password
respectively
or, if either is
missing,
you will be prompted from
the terminal.
It is probably better to let
.B rdate
prompt for the password as it
is more secure (it will not echo.)
.PP
The
.B \-s
flag is for server mode and causes
.B rdate
to simply put out the system's current
date and time in a format that can be
executed to set the date and time.
This is the form that is used on the remote
machine by the local
.B rdate.
.PP
If the
.B \-t
flag is used
.B rdate
only prints the date command to the standard
output rather than actually setting the date.
This could be useful to check that the
remote system has a reasonable date
before actually setting it.
.SH FILES
/etc/hosts
.br
/etc/services
.SH SEE ALSO
rsh(1C), rexec(3X)
.SH AUTHOR
Barry Shein, Boston University Distributed Systems Group

--------------------CUT HERE rdate.c--------------------
#include <stdio.h>
#include <netdb.h>
#include <sys/time.h>

/*
 *	Very simple remote date routine for 4.2bsd
 *	Barry Shein, Boston University
 *
 *	The basic idea is that in one mode rdate remote-execs
 *	a copy of rdate on another machine with an appropiate
 *	flag. This remote rdate will produce the string for a
 *	UNIX date command which, when locally exec'd, will
 *	set the date.
 *	Net delays are not taken into account.
 */
#define RDATE	"/etc/rdate -s"
#define DEFHOST	"bu-cs"		/* YOUR REMOTE HOST HERE */
char *myname ;
int tflag = 0 ;
usage()
{
	fprintf(stderr,
		"Usage: %s [-s][-h host][-u user][-p passwd]\n",myname) ;
	exit(1) ;
}
main(argc,argv) int argc ; char **argv ;
{
	struct servent *s ;
	char *host = NULL, *user = NULL, *passwd = NULL ;
	char buf[BUFSIZ] ;
	int rfd, i ;
	char *getpass() ;

	myname = *argv ;
	--argc ;
	while(argc--)
	{
		++argv ;
		if(**argv == '-') switch((*argv)[1]) {
			case 'h' :	/* other remote host	*/
				if(argc < 1) usage() ;
				host = *++argv ;
				--argc ;
				break ;
			case 'u' :	/* user name to rexec under	*/
				if(argc < 1) usage() ;
				user = *++argv ;
				--argc ;
				break ;
			case 'p' :	/* passwd to rexec under	*/
					/* note: if omitted will use getpass */
				if(argc < 1) usage() ;
				passwd = *++argv ;
				--argc ;
				break ;
			case 's' :	/* I am the remote	*/
				rdate() ;
				exit(0) ;
			case 't' :	/* just testing		*/
				++tflag ;
				break ;
			default :
				usage() ;
		}
		else usage() ;
	}
	if(host == NULL) host = DEFHOST ;
	if(user == NULL)
	{
		printf("(%s) User: ",host) ;
		gets(buf) ;
		user = (char *) malloc(strlen(buf)+1) ;
		strcpy(user,buf) ;
	}
	if(passwd == NULL)
	{
		sprintf(buf,"(%s) Password: ",host) ;
		passwd = getpass(buf) ;
	}
	if((s = getservbyname("exec","tcp")) == NULL)
	{
		perror("exec/tcp") ;
		exit(1) ;
	}
	if((rfd = rexec(&host,s->s_port,user,passwd,RDATE,(int *)0)) < 0)
	{
		perror("rexec") ;
		exit(1) ;
	}
	if((i = read(rfd,buf,BUFSIZ)) <= 0)
	{
		fprintf(stderr,"protocol failure\n") ;
		exit(1) ;
	}
	buf[i] = '\0' ;
	/*
	 *	Should probably be some error checking
	 *	at the minimum, did we get a 'date' command
	 *	back?
	 */
	if(tflag)
	{
		i = 0 ;
		fputs(buf,stdout) ;
	}
	else i = system(buf) ;
	exit(i) ;
}
/*
 *	Rdate - just generate a UNIX date command for 'now'
 *	on the standard output
 */
rdate()
{
	long int d ;
	struct tm *t, *localtime() ;


	d = time(0) ;
	t = localtime(&d) ;
	printf("date %02d%02d%02d%02d%02d.%02d\n",
		t->tm_year,t->tm_mon+1,t->tm_mday,
		t->tm_hour,t->tm_min,t->tm_sec) ;
}