[comp.bugs.4bsd.ucb-fixes] ARTICLE #14

bostic@OKEEFFE.BERKELEY.EDU.UUCP (03/27/87)

The next four articles posted to comp.bugs.4bsd.ucb-fixes, ARTICLES
#13 through #16, will concern the upcoming DST problem.  They contain:

ARTICLE #13	A minimal fix, hopefully easy to install.  It contains
		fixes for both 4.2 and 4.3 BSD systems.  To install
		this fix, unshar ARTICLE #13 in an empty directory and
		follow the instructions contained in the README file.

ARTICLES #14, #15, #16
		What Berkeley has installed.  To install this fix, create a
		directory containing one other directory; the sub-directory
		should be called "tzone".  Unshar ARTICLES #15 and #16 in
		this sub-directory.  Unshar ARTICLE #14 in the top directory.
		Follow the instructions contained in the README file.

You are reading ARTICLE #14.

If you have any problems getting either package to work,
please contact me.

Keith Bostic
bostic@ucbvax.berkeley.edu
ucbvax!bostic
seismo!keith
+1 (415) 642-4948

... cut here ...

echo x - README
sed 's/^X//' >README << 'END-of-README'
X	These are the actual fixes that Berkeley has installed in response
Xto the 1987 DST problem.  It's basically the ctime package recently posted
Xto mod.sources by Robert Elz and Arthur Olsen, with a few minor hacks.
X	One change was the removal of tzsetwall(3) and its replacement by
Xunsetenv(3).  This was because programs which wish to use local clock time
Xwill probably also want any programs they fork off to also use local time.
XFor completeness, the setenv(3) call was also added.
X	Another was the behavior of the localtime(3) call when unable to
Xfind the "correct" time file.  The original source simply defaulted to GMT.
XThis package attempts to return local time if that's available, then tries
Xto return the kernel's version of local time and then defaults to GMT.
XFor a more complete description of its behavior, see the ctime(3) man page.
X	Also, the timezone(3) routine is still in place, and will probably
Xremain for the forseeable future.
X	Incidentally, the undocumented routine dysize(3) has been deleted;
Xyou should remove it from all local source, it's not going to come back.
XSee the include file "tzfile.h" for a macro that does the same thing, only
Xcorrectly.
X
X	The following files should have been provided:
X
X	README			# the file you're reading
X
X	ctime.3			# various man pages
X	date.1
X	getenv.3
X	tzfile.5
X
X	diff.Makefile.1		# various Makefile updates
X	diff.Makefile.2
X	diff.Makefile.3
X
X	ctime.c			# various source files
X	getenv.c
X	setenv.c
X	timezone.c
X	tzfile.h
X
X	diff.arpadate.c		# various diff files
X	diff.date.c
X	diff.kern_time.c
X	diff.lock.c
X	diff.main.c
X	diff.time.h
X
X	tzone			# the timezone directory containing:
X	Makefile, README, Theory, asia, australasia, etcetera,
X	europe, ialloc.c, northamerica, pacificnew, scheck.c,
X	solar87, systemv, zdump.8, zdump.c, zic.8, zic.c
X
XTo install:
X
XStep #1:
X	Install the new man pages in the indicated directories.
X
X	date.1			/usr/man/man1/date.1
X	ctime.3			/usr/man/man3/ctime.3
X	getenv.3		/usr/man/man3/getenv.3
X	tzfile.5		/usr/man/man5/tzfile.5
X
XStep #2:
X	Patch the following source with the indicated files:
X
X	/usr/src/lib/libc/gen/Makefile			diff.Makefile.1
X	/usr/src/etc/Makefile				diff.Makefile.2
X	/usr/src/include/Makefile			diff.Makefile.3
X	/sys/sys/kern_time.c				diff.kern_time.c
X	/usr/src/include/time.h				diff.time.h
X	/usr/src/usr.lib/sendmail/src/arpadate.c	diff.arpadate.c
X	/usr/src/usr.lib/sendmail/src/main.c		diff.main.c
X	/usr/src/ucb/lock.c				diff.lock.c
X	/usr/src/bin/date.c				diff.date.c
X
X	Add the following files to the appropriate directories,
X	overwriting the current file if necessary.
X
X	getenv.c		/usr/src/lib/libc/gen/getenv.c
X	setenv.c		/usr/src/lib/libc/gen/setenv.c
X	ctime.c			/usr/src/lib/libc/gen/ctime.c
X	timezone.c		/usr/src/lib/libc/gen/timezone.c
X	tzfile.h		/usr/src/include/tzfile.h
X
XStep #3:
X	Install the new include files; you should be able to go
X	to /usr/src/include and do a "make install".  If you can't,
X	just get "time.h" and "tzfile.h" into place in /usr/include.
X
XStep #4:
X	Make and install the C library; you should be able to go to
X	/usr/src/lib/libc and do a "make depend;make;make install".
X	If you can't, fix it so you can.  There's a minor gap here,
X	too; any programs compiled after step #5 and before step #6
X	is complete may think the date is slightly wrong.
X
XStep #5:
X	Make and install the timezone files.  First copy the timezone
X	directory into /usr/src/etc/tzone, you should be able to just
X	do a "cp -r tzone /usr/src/etc/tzone".  Then, edit
X	/usr/src/etc/tzone/Makefile and set LOCALTIME.
X
X	If you're EST, "LOCALTIME=US/Eastern"
X	If you're CST, "LOCALTIME=US/Central"
X	If you're MST, "LOCALTIME=US/Mountain"
X	If you're PST, "LOCALTIME=US/Pacific"
X
X	Everybody else, go through the README and figure out what is
X	correct.  You should then be able to do a "make; make install".
X	This will execute the program "zic" which installs the timezone
X	files in /etc/zoneinfo.  Check /etc/zoneinfo to make sure
X	everything got put in place.
X
X	For general information, the file "tzone/Theory" is of interest,
X	but not precisely accurate in terms of the current package.  It
X	is the original file as posted by Olsen and Elz and has not been
X	updated to reflect the Berkeley usage.
X
XStep #6:
X	Recompile and install the necessary programs.  If your system
X	hasn't been changed much, you should be able to just do a
X	"make;make install" in /usr/src.  Otherwise, the following
X	programs should be recompiled and installed.
X
Xsrc/bin		adb, ar, date, diff, login, ls, mail, make, pr, ps,
X		su, tar, tp, wall, who, write
Xsrc/etc		XNSrouted, ac, arff, comsat, cron, dmesg, dump, dumpfs,
X		fsck, ftpd, getty, halt, implog, inetd, named, restore,
X		ntalkd, rdump, reboot, rlogind, routed, rrestore, rshd,
X		rwhod, savecore, shutdown, syslogd, talkd, telnetd,
X		tftpd, timed
Xsrc/games	adventure, battlestar, boggle, mille, monop, snake
Xsrc/new		X/xclock, ansi, apl, courier, dipress, emacs, help,
X		hyper, icon, jove, kermit, mh, mmdf, news, nntp,
X		notes, pup, rcs, sumacc
Xsrc/old		512restor, berknet, dnd, dump.4.1, talk, vpr
Xsrc/ucb		Mail, dbx, ex, finger, fp, last, lastcomm, leave,
X		lisp, liszt, lock, logger, msgs, pascal, rdist,
X		rwho, script, sysline, systat, vgrind, vmstat, w
Xsrc/undoc	v6mail
Xsrc/usr.bin	ar11, at, calendar, efl usr.bin/xsend, find, learn,
X		refer, tip, uucp
Xsrc/usr.lib	libF77, libI77, libU77, libpc, lpr, sendmail
END-of-README
echo x - ctime.3
sed 's/^X//' >ctime.3 << 'END-of-ctime.3'
X.\" Copyright (c) 1980 Regents of the University of California.
X.\" All rights reserved.  The Berkeley software License Agreement
X.\" specifies the terms and conditions for redistribution.
X.\"
X.\"	@(#)ctime.3	6.7 (Berkeley) 3/22/87
X.\"
X.TH CTIME 3  "March 22, 1987"
X.UC 4
X.SH NAME
Xctime, localtime, gmtime, asctime, timezone, tzset \-  convert date and time to ASCII
X.SH SYNOPSIS
X.nf
X.B void tzset()
X.PP
X.B char *ctime(clock)
X.B time_t *clock;
X.PP
X.B #include <time.h>
X.PP
X.B char *asctime(tm)
X.B struct tm *tm;
X.PP
X.B struct tm *localtime(clock)
X.B time_t *clock;
X.PP
X.B struct tm *gmtime(clock)
X.B time_t *clock;
X.PP
X.B char *timezone(zone, dst)
X.fi
X.fi
X.SH DESCRIPTION
X\fITzset\fP uses the value of the environment variable \fBTZ\fP to
Xset up the time conversion information used by \fIlocaltime\fP.
X.PP
XIf \fBTZ\fP does not appear in the environment, the \fBTZDEFAULT\fP
Xfile (as defined in \fItzfile.h\fP) is used by \fIlocaltime\fP.  If
Xthis file fails for any reason, the GMT offset as provided by the
Xkernel is used.  In this case, DST is ignored, resulting in the time
Xbeing incorrect by some amount if DST is currently in effect.  If
Xthis fails for any reason, GMT is used.
X.PP
XIf \fBTZ\fP appears in the environment but its value is a null string,
XGreenwich Mean Time is used; if \fBTZ\fP appears and begins with a
Xslash, it is used as the absolute pathname of the \fItzfile\fP(5)-format
Xfile from which to read the time conversion information; if \fBTZ\fP
Xappears and begins with a character other than a slash, it's used as
Xa pathname relative to the system time conversion information directory,
Xdefined as \fBTZDIR\fP in the include file \fItzfile.h\fP.  If
Xthis file fails for any reason, GMT is used.
X.PP
XPrograms that always wish to use local wall clock time should explicitly
Xremove the environmental variable \fBTZ\fP with \fIunsetenv\fP(3).
X.PP
X\fICtime\fP converts a long integer, pointed to by \fIclock\fP,
Xsuch as returned by \fItime\fP(2) into ASCII and returns a pointer
Xto a 26-character string in the following form.  All the fields
Xhave constant width.
X.PP
X    Sun Sep 16 01:03:52 1973\\n\\0
X.PP
X.I Localtime
Xand
X.I gmtime
Xreturn pointers to structures containing
Xthe broken-down time.
X.I Localtime
Xcorrects for the time zone and possible daylight savings time;
X.I gmtime
Xconverts directly to GMT, which is the time UNIX uses.
X.I Asctime
Xconverts a broken-down time to ASCII and returns a pointer
Xto a 26-character string.
X.PP
XThe structure declaration from the include file is:
X.PP
X.RS
X.nf
X.nr .0 .8i+\w'int tm_isdst'u
X.ta .5i \n(.0u \n(.0u+\w'/* 0-000'u+1n
Xstruct tm {
X	int tm_sec;	/* 0-59	seconds */
X	int tm_min;	/* 0-59	minutes */
X	int tm_hour;	/* 0-23	hour */
X	int tm_mday;	/* 1-31	day of month */
X	int tm_mon;	/* 0-11	month */
X	int tm_year;	/* 0-	year \- 1900 */
X	int tm_wday;	/* 0-6	day of week (Sunday = 0) */
X	int tm_yday;	/* 0-365	day of year */
X	int tm_isdst;	/* flag:	daylight savings time in effect */
X	char **tm_zone;	/* abbreviation of timezone name */
X	long tm_gmtoff;	/* offset from GMT in seconds */
X};
X.fi
X.RE
X.PP
X\fITm_isdst\fP is non-zero if a time zone adjustment such as Daylight
XSavings time is in effect.
X.PP
X\fITm_gmtoff\fP is the offset (in seconds) of the time represented
Xfrom GMT, with positive values indicating East of Greenwich.
X.PP
X\fITimezone\fP remains for compatibility reasons only; it's impossible to
Xreliably map timezone's arguments (\fIzone\fP, a "minutes west of GMT" value
Xand \fIdst\fP, a "daylight saving time in effect" flag) to a time zone
Xabbreviation.
X.PP
XIf the environmental string \fITZNAME\fP exists, \fItimezone\fP returns
Xits value, unless it consists of two comma separated strings, in which
Xcase the second string is returned if \fIdst\fP is non-zero, else
Xthe first string.  If \fITZNAME\fP doesn't exist, \fIzone\fP is checked
Xfor equality with a built-in table of values, in which case \fItimezone\fP
Xreturns the time zone or daylight time zone abbreviation associated with
Xthat value.  If the requested \fIzone\fP does not appear in the table, the
Xdifference from GMT is returned; e.g. in Afghanistan,
X\fItimezone(-(60*4+30), 0)\fP is appropriate because it is 4:30 ahead of
XGMT, and the string \fBGMT+4:30\fP is returned.  Programs that in the
Xpast used the \fItimezone\fP function should return the zone name as
Xset by \fIlocaltime\fP to assure correctness.
X.SH FILES
X.ta \w'/etc/zoneinfo/localtime\0\0'u
X/etc/zoneinfo	time zone information directory
X.br
X/etc/zoneinfo/localtime	local time zone file
X.SH SEE ALSO
Xgettimeofday(2), getenv(3), time(3), tzfile(5), environ(7)
X.SH NOTE
XThe return values point to static data whose content is overwritten by
Xeach call.  The \fBtm_zone\fP field of a returned \fBstruct tm\fP
Xpoints to a static array of characters, which will also be overwritten
Xat the next call (and by calls to \fItzset\fP).
END-of-ctime.3
echo x - ctime.c
sed 's/^X//' >ctime.c << 'END-of-ctime.c'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * This file may be freely redistributed provided that this
X * notice remains attached.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)ctime.c	1.1 (Berkeley) 3/25/87";
X#endif LIBC_SCCS and not lint
X
X#include "sys/param.h"
X#include "sys/time.h"
X#include "tzfile.h"
X
Xchar *
Xctime(t)
Xtime_t *t;
X{
X	struct tm	*localtime();
X	char	*asctime();
X
X	return(asctime(localtime(t)));
X}
X
X/*
X** A la X3J11
X*/
X
Xchar *
Xasctime(timeptr)
Xregister struct tm *	timeptr;
X{
X	static char	wday_name[DAYS_PER_WEEK][3] = {
X		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
X	};
X	static char	mon_name[MONS_PER_YEAR][3] = {
X		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
X		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
X	};
X	static char	result[26];
X
X	(void) sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
X		wday_name[timeptr->tm_wday],
X		mon_name[timeptr->tm_mon],
X		timeptr->tm_mday, timeptr->tm_hour,
X		timeptr->tm_min, timeptr->tm_sec,
X		TM_YEAR_BASE + timeptr->tm_year);
X	return result;
X}
X
X#ifndef TRUE
X#define TRUE		1
X#define FALSE		0
X#endif /* !TRUE */
X
Xextern char *		getenv();
Xextern char *		strcpy();
Xextern char *		strcat();
Xstruct tm *		offtime();
X
Xstruct ttinfo {				/* time type information */
X	long		tt_gmtoff;	/* GMT offset in seconds */
X	int		tt_isdst;	/* used to set tm_isdst */
X	int		tt_abbrind;	/* abbreviation list index */
X};
X
Xstruct state {
X	int		timecnt;
X	int		typecnt;
X	int		charcnt;
X	time_t		ats[TZ_MAX_TIMES];
X	unsigned char	types[TZ_MAX_TIMES];
X	struct ttinfo	ttis[TZ_MAX_TYPES];
X	char		chars[TZ_MAX_CHARS + 1];
X};
X
Xstatic struct state	s;
X
Xstatic int		tz_is_set;
X
Xchar *			tzname[2] = {
X	"GMT",
X	"GMT"
X};
X
X#ifdef USG_COMPAT
Xtime_t			timezone = 0;
Xint			daylight = 0;
X#endif /* USG_COMPAT */
X
Xstatic long
Xdetzcode(codep)
Xchar *	codep;
X{
X	register long	result;
X	register int	i;
X
X	result = 0;
X	for (i = 0; i < 4; ++i)
X		result = (result << 8) | (codep[i] & 0xff);
X	return result;
X}
X
Xstatic
Xtzload(name)
Xregister char *	name;
X{
X	register int	i;
X	register int	fid;
X
X	if (name == 0 && (name = TZDEFAULT) == 0)
X		return -1;
X	{
X		register char *	p;
X		register int	doaccess;
X		char		fullname[MAXPATHLEN];
X
X		doaccess = name[0] == '/';
X		if (!doaccess) {
X			if ((p = TZDIR) == 0)
X				return -1;
X			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
X				return -1;
X			(void) strcpy(fullname, p);
X			(void) strcat(fullname, "/");
X			(void) strcat(fullname, name);
X			/*
X			** Set doaccess if '.' (as in "../") shows up in name.
X			*/
X			while (*name != '\0')
X				if (*name++ == '.')
X					doaccess = TRUE;
X			name = fullname;
X		}
X		if (doaccess && access(name, 4) != 0)
X			return -1;
X		if ((fid = open(name, 0)) == -1)
X			return -1;
X	}
X	{
X		register char *			p;
X		register struct tzhead *	tzhp;
X		char				buf[sizeof s];
X
X		i = read(fid, buf, sizeof buf);
X		if (close(fid) != 0 || i < sizeof *tzhp)
X			return -1;
X		tzhp = (struct tzhead *) buf;
X		s.timecnt = (int) detzcode(tzhp->tzh_timecnt);
X		s.typecnt = (int) detzcode(tzhp->tzh_typecnt);
X		s.charcnt = (int) detzcode(tzhp->tzh_charcnt);
X		if (s.timecnt > TZ_MAX_TIMES ||
X			s.typecnt == 0 ||
X			s.typecnt > TZ_MAX_TYPES ||
X			s.charcnt > TZ_MAX_CHARS)
X				return -1;
X		if (i < sizeof *tzhp +
X			s.timecnt * (4 + sizeof (char)) +
X			s.typecnt * (4 + 2 * sizeof (char)) +
X			s.charcnt * sizeof (char))
X				return -1;
X		p = buf + sizeof *tzhp;
X		for (i = 0; i < s.timecnt; ++i) {
X			s.ats[i] = detzcode(p);
X			p += 4;
X		}
X		for (i = 0; i < s.timecnt; ++i)
X			s.types[i] = (unsigned char) *p++;
X		for (i = 0; i < s.typecnt; ++i) {
X			register struct ttinfo *	ttisp;
X
X			ttisp = &s.ttis[i];
X			ttisp->tt_gmtoff = detzcode(p);
X			p += 4;
X			ttisp->tt_isdst = (unsigned char) *p++;
X			ttisp->tt_abbrind = (unsigned char) *p++;
X		}
X		for (i = 0; i < s.charcnt; ++i)
X			s.chars[i] = *p++;
X		s.chars[i] = '\0';	/* ensure '\0' at end */
X	}
X	/*
X	** Check that all the local time type indices are valid.
X	*/
X	for (i = 0; i < s.timecnt; ++i)
X		if (s.types[i] >= s.typecnt)
X			return -1;
X	/*
X	** Check that all abbreviation indices are valid.
X	*/
X	for (i = 0; i < s.typecnt; ++i)
X		if (s.ttis[i].tt_abbrind >= s.charcnt)
X			return -1;
X	/*
X	** Set tzname elements to initial values.
X	*/
X	tzname[0] = tzname[1] = &s.chars[0];
X#ifdef USG_COMPAT
X	timezone = s.ttis[0].tt_gmtoff;
X	daylight = 0;
X#endif /* USG_COMPAT */
X	for (i = 1; i < s.typecnt; ++i) {
X		register struct ttinfo *	ttisp;
X
X		ttisp = &s.ttis[i];
X		if (ttisp->tt_isdst) {
X			tzname[1] = &s.chars[ttisp->tt_abbrind];
X#ifdef USG_COMPAT
X			daylight = 1;
X#endif /* USG_COMPAT */ 
X		} else {
X			tzname[0] = &s.chars[ttisp->tt_abbrind];
X#ifdef USG_COMPAT
X			timezone = ttisp->tt_gmtoff;
X#endif /* USG_COMPAT */ 
X		}
X	}
X	return 0;
X}
X
Xstatic
Xtzsetkernel()
X{
X	struct timeval	tv;
X	struct timezone	tz;
X	char	*tztab();
X
X	if (gettimeofday(&tv, &tz))
X		return -1;
X	s.timecnt = 0;		/* UNIX counts *west* of Greenwich */
X	s.ttis[0].tt_gmtoff = tz.tz_minuteswest * -SECS_PER_MIN;
X	s.ttis[0].tt_abbrind = 0;
X	(void)strcpy(s.chars, tztab(tz.tz_minuteswest, 0));
X	tzname[0] = tzname[1] = s.chars;
X#ifdef USG_COMPAT
X	timezone = tz.tz_minuteswest * 60;
X	daylight = tz.tz_dsttime;
X#endif /* USG_COMPAT */
X	return 0;
X}
X
Xstatic
Xtzsetgmt()
X{
X	s.timecnt = 0;
X	s.ttis[0].tt_gmtoff = 0;
X	s.ttis[0].tt_abbrind = 0;
X	(void) strcpy(s.chars, "GMT");
X	tzname[0] = tzname[1] = s.chars;
X#ifdef USG_COMPAT
X	timezone = 0;
X	daylight = 0;
X#endif /* USG_COMPAT */
X}
X
Xvoid
Xtzset()
X{
X	register char *	name;
X
X	tz_is_set = TRUE;
X	name = getenv("TZ");
X	if (!name || *name) {			/* did not request GMT */
X		if (name && !tzload(name))	/* requested name worked */
X			return;
X		if (!tzload((char *)0))		/* default name worked */
X			return;
X		if (!tzsetkernel())		/* kernel guess worked */
X			return;
X	}
X	tzsetgmt();				/* GMT is default */
X}
X
Xstruct tm *
Xlocaltime(timep)
Xtime_t *	timep;
X{
X	register struct ttinfo *	ttisp;
X	register struct tm *		tmp;
X	register int			i;
X	time_t				t;
X
X	if (!tz_is_set)
X		(void) tzset();
X	t = *timep;
X	if (s.timecnt == 0 || t < s.ats[0]) {
X		i = 0;
X		while (s.ttis[i].tt_isdst)
X			if (++i >= s.timecnt) {
X				i = 0;
X				break;
X			}
X	} else {
X		for (i = 1; i < s.timecnt; ++i)
X			if (t < s.ats[i])
X				break;
X		i = s.types[i - 1];
X	}
X	ttisp = &s.ttis[i];
X	/*
X	** To get (wrong) behavior that's compatible with System V Release 2.0
X	** you'd replace the statement below with
X	**	tmp = offtime((time_t) (t + ttisp->tt_gmtoff), 0L);
X	*/
X	tmp = offtime(&t, ttisp->tt_gmtoff);
X	tmp->tm_isdst = ttisp->tt_isdst;
X	tzname[tmp->tm_isdst] = &s.chars[ttisp->tt_abbrind];
X	tmp->tm_zone = &s.chars[ttisp->tt_abbrind];
X	return tmp;
X}
X
Xstruct tm *
Xgmtime(clock)
Xtime_t *	clock;
X{
X	register struct tm *	tmp;
X
X	tmp = offtime(clock, 0L);
X	tzname[0] = "GMT";
X	tmp->tm_zone = "GMT";		/* UCT ? */
X	return tmp;
X}
X
Xstatic int	mon_lengths[2][MONS_PER_YEAR] = {
X	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
X	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
X};
X
Xstatic int	year_lengths[2] = {
X	DAYS_PER_NYEAR, DAYS_PER_LYEAR
X};
X
Xstruct tm *
Xofftime(clock, offset)
Xtime_t *	clock;
Xlong		offset;
X{
X	register struct tm *	tmp;
X	register long		days;
X	register long		rem;
X	register int		y;
X	register int		yleap;
X	register int *		ip;
X	static struct tm	tm;
X
X	tmp = &tm;
X	days = *clock / SECS_PER_DAY;
X	rem = *clock % SECS_PER_DAY;
X	rem += offset;
X	while (rem < 0) {
X		rem += SECS_PER_DAY;
X		--days;
X	}
X	while (rem >= SECS_PER_DAY) {
X		rem -= SECS_PER_DAY;
X		++days;
X	}
X	tmp->tm_hour = (int) (rem / SECS_PER_HOUR);
X	rem = rem % SECS_PER_HOUR;
X	tmp->tm_min = (int) (rem / SECS_PER_MIN);
X	tmp->tm_sec = (int) (rem % SECS_PER_MIN);
X	tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYS_PER_WEEK);
X	if (tmp->tm_wday < 0)
X		tmp->tm_wday += DAYS_PER_WEEK;
X	y = EPOCH_YEAR;
X	if (days >= 0)
X		for ( ; ; ) {
X			yleap = isleap(y);
X			if (days < (long) year_lengths[yleap])
X				break;
X			++y;
X			days = days - (long) year_lengths[yleap];
X		}
X	else do {
X		--y;
X		yleap = isleap(y);
X		days = days + (long) year_lengths[yleap];
X	} while (days < 0);
X	tmp->tm_year = y - TM_YEAR_BASE;
X	tmp->tm_yday = (int) days;
X	ip = mon_lengths[yleap];
X	for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
X		days = days - (long) ip[tmp->tm_mon];
X	tmp->tm_mday = (int) (days + 1);
X	tmp->tm_isdst = 0;
X	tmp->tm_zone = "";
X	tmp->tm_gmtoff = offset;
X	return tmp;
X}
END-of-ctime.c
echo x - date.1
sed 's/^X//' >date.1 << 'END-of-date.1'
X.\" Copyright (c) 1980 Regents of the University of California.
X.\" All rights reserved.  The Berkeley software License Agreement
X.\" specifies the terms and conditions for redistribution.
X.\"
X.\"	@(#)date.1	6.5 (Berkeley) 3/24/87
X.\"
X.TH DATE 1 "March 24, 1987"
X.UC 4
X.SH NAME
Xdate \- print and set the date
X.SH SYNOPSIS
X.B date
X.RB "[-nu] [-d dst] [-t timezone] [yymmddhhmm [" . "ss] ]"
X.SH DESCRIPTION
XIf no arguments are given, the current date and time are printed.
XProviding an argument will set the desired date; only the superuser
Xcan set the date.  The \fI-d\fP and \fI-t\fP flags set the kernel's
Xvalues for daylight savings time and minutes west of GMT.  If \fIdst\fP
Xis non-zero, future calls to \fIgettimeofday\fP(2) will return a non-zero
X\fItz_dsttime\fP.  \fITimezone\fP provides the number of minutes returned
Xby future calls to \fIgettimeofday\fP(2) in \fItz_minuteswest\fP.  The
X\fI-u\fP flag is used to display or set the date in GMT (universal) time.
X.I yy
Xrepresents the last two digits of the year;
Xthe first
X.I mm
Xis the month number;
X.I dd
Xis the day number;
X.I hh
Xis the hour number (24 hour system);
Xthe second
X.I mm
Xis the minute number;
X.BI . ss
Xis optional and represents the seconds.
XFor example:
X.IP
Xdate 8506131627
X.PP
Xsets the date to June 13 1985, 4:27 PM.  The year, month and day may
Xbe omitted; the default values will be the current ones.  The system
Xoperates in GMT.  \fIDate\fP takes care of the conversion to and from
Xlocal standard and daylight-saving time.
X.PP
XIf 
X.I timed(8)
Xis running to synchronize the clocks of machines in a local
Xarea network, \fIdate\fP sets the time globally on all those
Xmachines unless the
X.B \-n
Xoption is given.
X.SH FILES
X/usr/adm/wtmp to record time-setting.
XIn /usr/adm/messages, \fIdate\fP records the name of the user
Xsetting the time.
X.SH SEE ALSO
Xgettimeofday(2), utmp(5), timed(8),
X.br
X\fITSP: The Time Synchronization Protocol for UNIX 4.3BSD\fP, 
XR. Gusella and S. Zatti
X.SH DIAGNOSTICS
XExit status is 0 on success, 1 on complete failure to set the date,
Xand 2 on successfully setting the local date but failing globally.
X.PP
XOccasionally, when \fItimed\fP synchronizes the time on many hosts, 
Xthe setting of a new time value may require more than a few seconds.
XOn these occasions, \fIdate\fP prints: `Network time being set'.
XThe message `Communication error with timed' occurs when the communication
Xbetween \fIdate\fP and \fItimed\fP fails.
X.SH BUGS
XThe system attempts to keep the date in a format closely compatible
Xwith VMS.  VMS, however, uses local time (rather than GMT) and does
Xnot understand daylight-saving time.  Thus, if you use both UNIX
Xand VMS, VMS will be running on GMT.
END-of-date.1
echo x - diff.Makefile.1
sed 's/^X//' >diff.Makefile.1 << 'END-of-diff.Makefile.1'
X*** Makefile	Tue Mar 24 09:39:07 1987
X--- Makefile.new	Tue Mar 24 09:40:49 1987
X***************
X*** 28,34 ****
X  	regex.c scandir.c seekdir.c setgid.c setegid.c setrgid.c setuid.c \
X  	seteuid.c setruid.c siglist.c signal.c siginterrupt.c sleep.c \
X  	swab.c syslog.c system.c telldir.c time.c timezone.c ttyname.c \
X! 	ttyslot.c ualarm.c usleep.c valloc.c
X  VAXSRC=	index.c rindex.c strcat.c strcmp.c strcpy.c strlen.c \
X  	strncat.c strncmp.c strncpy.c
X  STDOBJ=	abort.o alarm.o atoi.o atol.o calloc.o closedir.o crypt.o \
X--- 28,34 ----
X  	regex.c scandir.c seekdir.c setgid.c setegid.c setrgid.c setuid.c \
X  	seteuid.c setruid.c siglist.c signal.c siginterrupt.c sleep.c \
X  	swab.c syslog.c system.c telldir.c time.c timezone.c ttyname.c \
X! 	ttyslot.c ualarm.c usleep.c valloc.c setenv.c
X  VAXSRC=	index.c rindex.c strcat.c strcmp.c strcpy.c strlen.c \
X  	strncat.c strncmp.c strncpy.c
X  STDOBJ=	abort.o alarm.o atoi.o atol.o calloc.o closedir.o crypt.o \
X***************
X*** 40,46 ****
X  	regex.o scandir.o seekdir.o setgid.o setegid.o setrgid.o setuid.o \
X  	seteuid.o setruid.o siglist.o signal.o siginterrupt.o sleep.o \
X  	swab.o syslog.o system.o telldir.o time.o timezone.o ttyname.o \
X! 	ttyslot.o ualarm.o usleep.o valloc.o
X  VAXOBJ=	index.o rindex.o strcat.o strcmp.o strcpy.o strlen.o \
X  	strncat.o strncmp.o strncpy.o
X  TAGSFILE=tags
X--- 40,46 ----
X  	regex.o scandir.o seekdir.o setgid.o setegid.o setrgid.o setuid.o \
X  	seteuid.o setruid.o siglist.o signal.o siginterrupt.o sleep.o \
X  	swab.o syslog.o system.o telldir.o time.o timezone.o ttyname.o \
X! 	ttyslot.o ualarm.o usleep.o valloc.o setenv.o
X  VAXOBJ=	index.o rindex.o strcat.o strcmp.o strcpy.o strlen.o \
X  	strncat.o strncmp.o strncpy.o
X  TAGSFILE=tags
END-of-diff.Makefile.1
echo x - diff.Makefile.2
sed 's/^X//' >diff.Makefile.2 << 'END-of-diff.Makefile.2'
X*** Makefile	Tue Mar 24 09:42:03 1987
X--- Makefile.new	Tue Mar 24 09:42:24 1987
X***************
X*** 11,17 ****
X  # Programs that live in subdirectories, and have makefiles of their own.
X  #
X  SUBDIR=	config dump dump.4.1 fsck ftpd getty htable implog named restore \
X! 	routed talkd termcap tftpd timed XNSrouted
X  
X  # Shell scripts that need only be installed and are never removed.
X  #
X--- 11,17 ----
X  # Programs that live in subdirectories, and have makefiles of their own.
X  #
X  SUBDIR=	config dump dump.4.1 fsck ftpd getty htable implog named restore \
X! 	routed talkd termcap tftpd timed tzone XNSrouted
X  
X  # Shell scripts that need only be installed and are never removed.
X  #
END-of-diff.Makefile.2
echo x - diff.Makefile.3
sed 's/^X//' >diff.Makefile.3 << 'END-of-diff.Makefile.3'
X*** Makefile	Tue Mar 24 09:43:33 1987
X--- Makefile.new	Tue Mar 24 09:43:57 1987
X***************
X*** 22,28 ****
X  	fcntl.h fstab.h grp.h lastlog.h math.h memory.h mp.h mtab.h \
X  	netdb.h nlist.h pcc.h pwd.h ranlib.h resolv.h setjmp.h \
X  	sgtty.h stab.h stdio.h string.h strings.h struct.h syscall.h \
X! 	sysexits.h time.h ttyent.h utmp.h varargs.h vfont.h
X  LINKS=	errno.h signal.h syslog.h
X  MACHINE=vax
X  MACHDEP=${MACHINE} vaxif vaxmba vaxuba
X--- 22,28 ----
X  	fcntl.h fstab.h grp.h lastlog.h math.h memory.h mp.h mtab.h \
X  	netdb.h nlist.h pcc.h pwd.h ranlib.h resolv.h setjmp.h \
X  	sgtty.h stab.h stdio.h string.h strings.h struct.h syscall.h \
X! 	sysexits.h time.h ttyent.h tzfile.h utmp.h varargs.h vfont.h
X  LINKS=	errno.h signal.h syslog.h
X  MACHINE=vax
X  MACHDEP=${MACHINE} vaxif vaxmba vaxuba
END-of-diff.Makefile.3
echo x - diff.arpadate.c
sed 's/^X//' >diff.arpadate.c << 'END-of-diff.arpadate.c'
X*** /nbsd/usr/src/usr.lib/sendmail/src/arpadate.c	Thu Jan  9 15:19:40 1986
X--- /usr/src/usr.lib/sendmail/src/arpadate.c	Sun Mar 22 13:12:41 1987
X***************
X*** 9,15 ****
X  */
X  
X  #ifndef lint
X! static char	SccsId[] = "@(#)arpadate.c	5.4 (Berkeley) 1/9/86";
X  #endif not lint
X  
X  # include "conf.h"
X--- 9,15 ----
X  */
X  
X  #ifndef lint
X! static char	SccsId[] = "@(#)arpadate.c	5.5 (Berkeley) 3/18/87";
X  #endif not lint
X  
X  # include "conf.h"
X***************
X*** 74,80 ****
X  # else OLDTIME
X  	struct timeb t;
X  	extern struct timeb *ftime();
X- 	extern char *timezone();
X  # endif OLDTIME
X  # ifdef V6
X  	extern char *StdTimezone, *DstTimezone;
X--- 74,79 ----
X***************
X*** 148,154 ****
X  	else
X  		p = tzname[0];
X  # else
X! 	p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
X  # endif USG
X  # endif V6
X  	if ((strncmp(p, "GMT", 3) == 0 || strncmp(p, "gmt", 3) == 0) &&
X--- 147,153 ----
X  	else
X  		p = tzname[0];
X  # else
X! 	p = localtime(&t.time)->tm_zone;
X  # endif USG
X  # endif V6
X  	if ((strncmp(p, "GMT", 3) == 0 || strncmp(p, "gmt", 3) == 0) &&
END-of-diff.arpadate.c
echo x - diff.date.c
sed 's/^X//' >diff.date.c << 'END-of-diff.date.c'
X*** /nbsd/usr/src/bin/date.c	Sun May 18 21:43:36 1986
X--- /usr/src/bin/date.c	Tue Mar 24 13:03:02 1987
X***************
X*** 11,17 ****
X  #endif not lint
X  
X  #ifndef lint
X! static char sccsid[] = "@(#)date.c	4.19 (Berkeley) 5/18/86";
X  #endif not lint
X  
X  /*
X--- 11,17 ----
X  #endif not lint
X  
X  #ifndef lint
X! static char sccsid[] = "@(#)date.c	4.20 (Berkeley) 3/24/87";
X  #endif not lint
X  
X  /*
X***************
X*** 19,223 ****
X   */
X  
X  #include <sys/param.h>
X- #include <stdio.h>
X  #include <sys/time.h>
X  #include <sys/file.h>
X  #include <errno.h>
X  #include <syslog.h>
X  #include <utmp.h>
X  
X! #define WTMP	"/usr/adm/wtmp"
X  
X! struct	timeval tv, now;
X! struct	timezone tz;
X! char	*ap, *ep, *sp;
X! int	uflag, nflag;
X! int	retval;
X  
X! char	*timezone();
X! static	int dmsize[12] =
X!     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
X! static	char *usage = "usage: date [-n] [-u] [yymmddhhmm[.ss]]\n";
X  
X! struct utmp wtmp[2] = {
X  	{ "|", "", "", 0 },
X  	{ "{", "", "", 0 }
X  };
X  
X! char	*ctime();
X! char	*asctime();
X! struct	tm *localtime();
X! struct	tm *gmtime();
X! char	*strcpy(), *strncpy();
X! char	*username, *getlogin();
X! long	time();
X! uid_t	getuid();
X! 
X! main(argc, argv)
X! 	int argc;
X! 	char *argv[];
X  {
X! 	register char *tzn;
X  
X! 	openlog("date", LOG_ODELAY, LOG_AUTH);
X! 	(void) gettimeofday(&tv, &tz);
X! 	now = tv;
X! 
X! 	while (argc > 1 && argv[1][0] == '-') {
X! 		while (*++argv[1])
X! 		    switch ((int)argv[1][0]) {
X! 
X! 		    case 'n':
X! 			nflag++;
X  			break;
X! 
X! 		    case 'u':
X! 			uflag++;
X  			break;
X! 
X! 		    default:
X! 			fprintf(stderr, usage);
X  			exit(1);
X  		}
X! 		argc--;
X! 		argv++;
X! 	}
X! 	if (argc > 2) {
X! 		fprintf(stderr, usage);
X  		exit(1);
X  	}
X- 	if (argc == 1) 
X- 		goto display;
X  
X! 	if (getuid() != 0) {
X! 		fprintf(stderr, "You are not superuser: date not set\n");
X  		retval = 1;
X  		goto display;
X  	}
X- 	username = getlogin();
X- 	if (username == NULL || *username == '\0')  /* single-user or no tty */
X- 		username = "root";
X  
X! 	ap = argv[1];
X  	wtmp[0].ut_time = tv.tv_sec;
X! 	if (gtime()) {
X! 		fprintf(stderr, usage);
X  		retval = 1;
X  		goto display;
X  	}
X! 	/* convert to GMT assuming local time */
X! 	if (uflag == 0) {
X! 		tv.tv_sec += (long)tz.tz_minuteswest*60;
X! 		/* now fix up local daylight time */
X  		if (localtime((time_t *)&tv.tv_sec)->tm_isdst)
X! 			tv.tv_sec -= 60*60;
X  	}
X! 	if (nflag || !settime(tv)) {
X! 		int wf;
X! 
X! 		if (settimeofday(&tv, (struct timezone *)0) < 0) {
X  			perror("settimeofday");
X  			retval = 1;
X  			goto display;
X  		}
X! 		if ((wf = open(WTMP, O_WRONLY|O_APPEND)) >= 0) {
X! 			(void) time((time_t *)&wtmp[1].ut_time);
X! 			(void) write(wf, (char *)wtmp, sizeof(wtmp));
X! 			(void) close(wf);
X  		}
X  	}
X- 	syslog(LOG_NOTICE, "set by %s", username);
X  
X  display:
X! 	(void) gettimeofday(&tv, (struct timezone *)0);
X  	if (uflag) {
X  		ap = asctime(gmtime((time_t *)&tv.tv_sec));
X  		tzn = "GMT";
X! 	} else {
X! 		struct tm *tp;
X  		tp = localtime((time_t *)&tv.tv_sec);
X  		ap = asctime(tp);
X! 		tzn = timezone(tz.tz_minuteswest, tp->tm_isdst);
X  	}
X! 	printf("%.20s", ap);
X! 	if (tzn)
X! 		printf("%s", tzn);
X! 	printf("%s", ap+19);
X  	exit(retval);
X  }
X  
X! gtime()
X  {
X! 	register int i, year, month;
X! 	int day, hour, mins, secs;
X! 	struct tm *L;
X! 	char x;
X  
X! 	ep = ap;
X! 	while(*ep) ep++;
X! 	sp = ap;
X! 	while(sp < ep) {
X! 		x = *sp;
X! 		*sp++ = *--ep;
X! 		*ep = x;
X  	}
X! 	sp = ap;
X! 	(void) gettimeofday(&tv, (struct timezone *)0);
X  	L = localtime((time_t *)&tv.tv_sec);
X! 	secs = gp(-1);
X! 	if (*sp != '.') {
X! 		mins = secs;
X! 		secs = 0;
X! 	} else {
X! 		sp++;
X! 		mins = gp(-1);
X  	}
X! 	hour = gp(-1);
X! 	day = gp(L->tm_mday);
X! 	month = gp(L->tm_mon+1);
X! 	year = gp(L->tm_year);
X! 	if (*sp)
X! 		return (1);
X! 	if (month < 1 || month > 12 ||
X! 	    day < 1 || day > 31 ||
X! 	    mins < 0 || mins > 59 ||
X! 	    secs < 0 || secs > 59)
X! 		return (1);
X  	if (hour == 24) {
X  		hour = 0;
X- 		day++;
X  	}
X! 	if (hour < 0 || hour > 23)
X! 		return (1);
X  	tv.tv_sec = 0;
X! 	year += 1900;
X! 	for (i = 1970; i < year; i++)
X! 		tv.tv_sec += dysize(i);
X! 	/* Leap year */
X! 	if (dysize(year) == 366 && month >= 3)
X! 		tv.tv_sec++;
X  	while (--month)
X! 		tv.tv_sec += dmsize[month-1];
X! 	tv.tv_sec += day-1;
X! 	tv.tv_sec = 24*tv.tv_sec + hour;
X! 	tv.tv_sec = 60*tv.tv_sec + mins;
X! 	tv.tv_sec = 60*tv.tv_sec + secs;
X! 	return (0);
X  }
X  
X- gp(dfault)
X- {
X- 	register int c, d;
X- 
X- 	if (*sp == 0)
X- 		return (dfault);
X- 	c = (*sp++) - '0';
X- 	d = (*sp ? (*sp++) - '0' : 0);
X- 	if (c < 0 || c > 9 || d < 0 || d > 9)
X- 		return (-1);
X- 	return (c+10*d);
X- }
X- 
X  #include <sys/socket.h>
X  #include <netinet/in.h>
X  #include <netdb.h>
X--- 19,232 ----
X   */
X  
X  #include <sys/param.h>
X  #include <sys/time.h>
X  #include <sys/file.h>
X  #include <errno.h>
X  #include <syslog.h>
X  #include <utmp.h>
X+ #include <tzfile.h>
X+ #include <stdio.h>
X+ #include <ctype.h>
X+ #include <strings.h>
X  
X! #define	WTMP		"/usr/adm/wtmp"
X! #define	ATOI2(ar)	(ar[0] - '0') * 10 + (ar[1] - '0'); ar += 2;
X  
X! static struct timeval	tv;
X! static int	retval;
X  
X! static int	dmsize[] =
X! 	{ -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
X  
X! static struct utmp	wtmp[2] = {
X  	{ "|", "", "", 0 },
X  	{ "{", "", "", 0 }
X  };
X  
X! main(argc,argv)
X! 	int	argc;
X! 	char	**argv;
X  {
X! 	extern int	optind;
X! 	extern char	*optarg;
X! 	static char	usage[] = "usage: date [-nu] [-d dst] [-t timezone] [yymmddhhmm[.ss]]\n";
X! 	struct timezone	tz;
X! 	char	*ap,			/* time string */
X! 		*tzn;			/* time zone */
X! 	int	ch,			/* getopts char */
X! 		uflag,			/* do it in GMT */
X! 		nflag,			/* only set time locally */
X! 		wf;			/* wtmp file descriptor */
X! 	long	time();
X! 	uid_t	getuid();
X! 	char	*username, *getlogin();
X  
X! 	nflag = uflag = 0;
X! 	while ((ch = getopt(argc,argv,"d:nut:")) != EOF)
X! 		switch((char)ch) {
X! 		case 'd':
X! 			tz.tz_dsttime = atoi(optarg) ? 1 : 0;
X  			break;
X! 		case 'n':
X! 			nflag = 1;
X  			break;
X! 		case 't':
X! 			tz.tz_minuteswest = atoi(optarg);
X! 			break;
X! 		case 'u':
X! 			uflag = 1;
X! 			break;
X! 		default:
X! 			fputs(usage,stderr);
X  			exit(1);
X  		}
X! 	argc -= optind;
X! 	argv += optind;
X! 
X! 	if (argc > 1) {
X! 		fputs(usage,stderr);
X  		exit(1);
X  	}
X  
X! 	if ((tz.tz_minuteswest || tz.tz_dsttime) &&
X! 	    settimeofday((struct timeval *)NULL,&tz)) {
X! 		perror("settimeofday");
X  		retval = 1;
X  		goto display;
X  	}
X  
X! 	if (gettimeofday(&tv,&tz)) {
X! 		perror("gettimeofday");
X! 		exit(1);
X! 	}
X! 
X! 	if (!argc)
X! 		goto display;
X! 
X  	wtmp[0].ut_time = tv.tv_sec;
X! 	if (gtime(*argv)) {
X! 		fputs(usage,stderr);
X  		retval = 1;
X  		goto display;
X  	}
X! 
X! 	if (!uflag) {		/* convert to GMT assuming local time */
X! 		tv.tv_sec += (long)tz.tz_minuteswest * SECS_PER_MIN;
X! 				/* now fix up local daylight time */
X  		if (localtime((time_t *)&tv.tv_sec)->tm_isdst)
X! 			tv.tv_sec -= SECS_PER_HOUR;
X  	}
X! 	if (nflag || !netsettime(tv)) {
X! 		if (settimeofday(&tv,(struct timezone *)0)) {
X  			perror("settimeofday");
X  			retval = 1;
X  			goto display;
X  		}
X! 		if ((wf = open(WTMP,O_WRONLY|O_APPEND)) < 0)
X! 			fputs("date: can't write wtmp file.\n",stderr);
X! 		else {
X! 			(void)time((time_t *)&wtmp[1].ut_time);
X! 			/*NOSTRICT*/
X! 			(void)write(wf,(char *)wtmp,sizeof(wtmp));
X! 			(void)close(wf);
X  		}
X  	}
X  
X+ 	username = getlogin();
X+ 	if (!username || *username == '\0')	/* single-user or no tty */
X+ 		username = "root";
X+ 	syslog(LOG_AUTH | LOG_NOTICE,"date set by %s",username);
X+ 
X  display:
X! 	if (gettimeofday(&tv,(struct timezone *)0)) {
X! 		perror("gettimeofday");
X! 		exit(1);
X! 	}
X  	if (uflag) {
X  		ap = asctime(gmtime((time_t *)&tv.tv_sec));
X  		tzn = "GMT";
X! 	}
X! 	else {
X! 		struct tm	*tp;
X! 
X  		tp = localtime((time_t *)&tv.tv_sec);
X  		ap = asctime(tp);
X! 		tzn = tp->tm_zone;
X  	}
X! 	printf("%.20s%s%s",ap,tzn,ap + 19);
X  	exit(retval);
X  }
X  
X! /*
X!  * gtime --
X!  *	convert user's time into number of seconds
X!  */
X! static
X! gtime(ap)
X! 	register char	*ap;		/* user argument */
X  {
X! 	register int	year, month;
X! 	register char	*C;		/* pointer into time argument */
X! 	struct tm	*L;
X! 	int	day, hour, mins, secs;
X  
X! 	for (secs = 0, C = ap;*C;++C) {
X! 		if (*C == '.') {		/* seconds provided */
X! 			if (strlen(C) != 3)
X! 				return(1);
X! 			*C = NULL;
X! 			secs = (C[1] - '0') * 10 + (C[2] - '0');
X! 			break;
X! 		}
X! 		if (!isdigit(*C))
X! 			return(-1);
X  	}
X! 
X  	L = localtime((time_t *)&tv.tv_sec);
X! 	year = L->tm_year;			/* defaults */
X! 	month = L->tm_mon + 1;
X! 	day = L->tm_mday;
X! 
X! 	switch ((int)(C - ap)) {		/* length */
X! 		case 10:			/* yymmddhhmm */
X! 			year = ATOI2(ap);
X! 		case 8:				/* mmddhhmm */
X! 			month = ATOI2(ap);
X! 		case 6:				/* ddhhmm */
X! 			day = ATOI2(ap);
X! 		case 4:				/* hhmm */
X! 			hour = ATOI2(ap);
X! 			mins = ATOI2(ap);
X! 			break;
X! 		default:
X! 			return(1);
X  	}
X! 
X! 	if (*ap || month < 1 || month > 12 || day < 1 || day > 31 ||
X! 	     mins < 0 || mins > 59 || secs < 0 || secs > 59)
X! 		return(1);
X  	if (hour == 24) {
X+ 		++day;
X  		hour = 0;
X  	}
X! 	else if (hour < 0 || hour > 23)
X! 		return(1);
X! 
X  	tv.tv_sec = 0;
X! 	year += TM_YEAR_BASE;
X! 	if (isleap(year) && month > 2)
X! 		++tv.tv_sec;
X! 	for (--year;year >= EPOCH_YEAR;--year)
X! 		tv.tv_sec += isleap(year) ? DAYS_PER_LYEAR : DAYS_PER_NYEAR;
X  	while (--month)
X! 		tv.tv_sec += dmsize[month];
X! 	tv.tv_sec += day - 1;
X! 	tv.tv_sec = HOURS_PER_DAY * tv.tv_sec + hour;
X! 	tv.tv_sec = MINS_PER_HOUR * tv.tv_sec + mins;
X! 	tv.tv_sec = SECS_PER_MIN * tv.tv_sec + secs;
X! 	return(0);
X  }
X  
X  #include <sys/socket.h>
X  #include <netinet/in.h>
X  #include <netdb.h>
X***************
X*** 236,243 ****
X   * notifies the master that a correction is needed.
X   * Returns 1 on success, 0 on failure.
X   */
X! settime(tv)
X! 	struct timeval tv;
X  {
X  	int s, length, port, timed_ack, found, err;
X  	long waittime;
X--- 245,253 ----
X   * notifies the master that a correction is needed.
X   * Returns 1 on success, 0 on failure.
X   */
X! static
X! netsettime(ntv)
X! 	struct timeval ntv;
X  {
X  	int s, length, port, timed_ack, found, err;
X  	long waittime;
X***************
X*** 250,259 ****
X  
X  	sp = getservbyname("timed", "udp");
X  	if (sp == 0) {
X! 		fprintf(stderr, "udp/timed: unknown service\n");
X  		retval = 2;
X  		return (0);
X! 	}	
X  	dest.sin_port = sp->s_port;
X  	dest.sin_family = AF_INET;
X  	dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
X--- 260,269 ----
X  
X  	sp = getservbyname("timed", "udp");
X  	if (sp == 0) {
X! 		fputs("udp/timed: unknown service\n",stderr);
X  		retval = 2;
X  		return (0);
X! 	}
X  	dest.sin_port = sp->s_port;
X  	dest.sin_family = AF_INET;
X  	dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
X***************
X*** 276,291 ****
X  		}
X  	}
X  	if (port == IPPORT_RESERVED / 2) {
X! 		fprintf(stderr, "date: All ports in use\n");
X  		goto bad;
X  	}
X  	msg.tsp_type = TSP_SETDATE;
X  	msg.tsp_vers = TSPVERSION;
X! 	(void) gethostname(hostname, sizeof (hostname));
X  	(void) strncpy(msg.tsp_name, hostname, sizeof (hostname));
X  	msg.tsp_seq = htons((u_short)0);
X! 	msg.tsp_time.tv_sec = htonl((u_long)tv.tv_sec);
X! 	msg.tsp_time.tv_usec = htonl((u_long)tv.tv_usec);
X  	length = sizeof (struct sockaddr_in);
X  	if (connect(s, &dest, length) < 0) {
X  		perror("date: connect");
X--- 286,304 ----
X  		}
X  	}
X  	if (port == IPPORT_RESERVED / 2) {
X! 		fputs("date: All ports in use\n",stderr);
X  		goto bad;
X  	}
X  	msg.tsp_type = TSP_SETDATE;
X  	msg.tsp_vers = TSPVERSION;
X! 	if (gethostname(hostname, sizeof (hostname))) {
X! 		perror("gethostname");
X! 		goto bad;
X! 	}
X  	(void) strncpy(msg.tsp_name, hostname, sizeof (hostname));
X  	msg.tsp_seq = htons((u_short)0);
X! 	msg.tsp_time.tv_sec = htonl((u_long)ntv.tv_sec);
X! 	msg.tsp_time.tv_usec = htonl((u_long)ntv.tv_usec);
X  	length = sizeof (struct sockaddr_in);
X  	if (connect(s, &dest, length) < 0) {
X  		perror("date: connect");
X***************
X*** 343,350 ****
X  		}
X  	}
X  	if (timed_ack == -1)
X! 		fprintf(stderr,
X! 		    "date: Can't reach time daemon, time set locally.\n");
X  bad:
X  	(void)close(s);
X  	retval = 2;
X--- 356,363 ----
X  		}
X  	}
X  	if (timed_ack == -1)
X! 		fputs("date: Can't reach time daemon, time set locally.\n",
X! 		    stderr);
X  bad:
X  	(void)close(s);
X  	retval = 2;
END-of-diff.date.c
echo x - diff.kern_time.c
sed 's/^X//' >diff.kern_time.c << 'END-of-diff.kern_time.c'
X*** kern_time.c	Wed Mar 25 18:01:40 1987
X--- /sys/sys/kern_time.c	Mon Mar 23 17:46:20 1987
X***************
X*** 3,13 ****
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)kern_time.c	7.1 (Berkeley) 6/5/86
X   */
X  
X- #include "../machine/reg.h"
X- 
X  #include "param.h"
X  #include "dir.h"		/* XXX */
X  #include "user.h"
X--- 3,11 ----
X   * All rights reserved.  The Berkeley software License Agreement
X   * specifies the terms and conditions for redistribution.
X   *
X!  *	@(#)kern_time.c	7.4 (Berkeley) 3/23/87
X   */
X  
X  #include "param.h"
X  #include "dir.h"		/* XXX */
X  #include "user.h"
X***************
X*** 15,20 ****
X--- 13,21 ----
X  #include "inode.h"
X  #include "proc.h"
X  
X+ #include "../machine/reg.h"
X+ #include "../machine/cpu.h"
X+ 
X  /* 
X   * Time of day and interval timer support.
X   *
X***************
X*** 33,46 ****
X  	} *uap = (struct a *)u.u_ap;
X  	struct timeval atv;
X  
X! 	microtime(&atv);
X! 	u.u_error = copyout((caddr_t)&atv, (caddr_t)uap->tp, sizeof (atv));
X! 	if (u.u_error)
X! 		return;
X! 	if (uap->tzp == 0)
X! 		return;
X! 	/* SHOULD HAVE PER-PROCESS TIMEZONE */
X! 	u.u_error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, sizeof (tz));
X  }
X  
X  settimeofday()
X--- 34,49 ----
X  	} *uap = (struct a *)u.u_ap;
X  	struct timeval atv;
X  
X! 	if (uap->tp) {
X! 		microtime(&atv);
X! 		u.u_error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
X! 			sizeof (atv));
X! 		if (u.u_error)
X! 			return;
X! 	}
X! 	if (uap->tzp)
X! 		u.u_error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
X! 			sizeof (tz));
X  }
X  
X  settimeofday()
X***************
X*** 52,62 ****
X  	struct timeval atv;
X  	struct timezone atz;
X  
X! 	u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
X! 		sizeof (struct timeval));
X! 	if (u.u_error)
X! 		return;
X! 	setthetime(&atv);
X  	if (uap->tzp && suser()) {
X  		u.u_error = copyin((caddr_t)uap->tzp, (caddr_t)&atz,
X  			sizeof (atz));
X--- 55,67 ----
X  	struct timeval atv;
X  	struct timezone atz;
X  
X! 	if (uap->tv) {
X! 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
X! 			sizeof (struct timeval));
X! 		if (u.u_error)
X! 			return;
X! 		setthetime(&atv);
X! 	}
X  	if (uap->tzp && suser()) {
X  		u.u_error = copyin((caddr_t)uap->tzp, (caddr_t)&atz,
X  			sizeof (atz));
X***************
X*** 174,180 ****
X  	splx(s);
X  	u.u_error = copyout((caddr_t)&aitv, (caddr_t)uap->itv,
X  	    sizeof (struct itimerval));
X- 	splx(s);
X  }
X  
X  setitimer()
X--- 179,184 ----
END-of-diff.kern_time.c
echo x - diff.lock.c
sed 's/^X//' >diff.lock.c << 'END-of-diff.lock.c'
X*** /nbsd/usr/src/ucb/lock.c	Fri May 31 09:20:06 1985
X--- /usr/src/ucb/lock.c	Wed Mar 18 15:21:51 1987
X***************
X*** 11,17 ****
X  #endif not lint
X  
X  #ifndef lint
X! static char sccsid[] = "@(#)lock.c	5.1 (Berkeley) 5/31/85";
X  #endif not lint
X  
X  /*
X--- 11,17 ----
X  #endif not lint
X  
X  #ifndef lint
X! static char sccsid[] = "@(#)lock.c	5.2 (Berkeley) 3/18/87";
X  #endif not lint
X  
X  /*
X***************
X*** 23,80 ****
X   * an argument of the form -time where time is in minutes
X   */
X  
X! #include <pwd.h>
X! #include <stdio.h>
X! #include <sys/types.h>
X  #include <sys/stat.h>
X  #include <sys/time.h>
X! #include <signal.h>
X  #include <sgtty.h>
X  
X! #define TIMEOUT 15
X  
X! struct	passwd *pwd;
X! char	*crypt();
X! char	*getpass();
X! char	*index();
X! char	*ttyname();
X! char	*timezone();
X! char	*asctime();
X! struct	tm *localtime();
X  
X! int	quit();
X! int	bye();
X! int	hi();
X! 
X! struct timeval	timeout	= {0, 0};
X! struct timeval	zerotime = {0, 0};
X  struct sgttyb	tty, ntty;
X  long	nexttime;		/* keep the timeout time */
X  
X! main(argc, argv)
X! 	int argc;
X! 	char **argv;
X  {
X! 	register int t;
X! 	char	*ttynam;
X! 	char	*ap;
X! 	int	sectimeout = TIMEOUT;
X! 	char	s[BUFSIZ], s1[BUFSIZ];
X! 	char	hostname[32];
X! 	char	*tzn;
X  	struct timeval	timval;
X  	struct itimerval	ntimer, otimer;
X- 	struct timezone	timzone;
X  	struct tm	*timp;
X! 	struct stat	statb;
X  
X! 	/* process arguments */
X  
X! 	if (argc > 1){
X! 		if (argv[1][0] != '-')
X! 			goto usage;
X! 		if (sscanf(&(argv[1][1]), "%d", &sectimeout) != 1)
X! 			goto usage;
X  	}
X  	timeout.tv_sec = sectimeout * 60;
X  
X--- 23,65 ----
X   * an argument of the form -time where time is in minutes
X   */
X  
X! #include <sys/param.h>
X  #include <sys/stat.h>
X  #include <sys/time.h>
X! #include <sys/signal.h>
X! #include <pwd.h>
X  #include <sgtty.h>
X+ #include <stdio.h>
X  
X! #define	TIMEOUT 15
X  
X! int	quit(), bye(), hi();
X  
X! struct timeval	timeout;
X! struct timeval	zerotime;
X  struct sgttyb	tty, ntty;
X  long	nexttime;		/* keep the timeout time */
X  
X! main(argc,argv)
X! 	int	argc;
X! 	char	**argv;
X  {
X! 	struct passwd	*pwd;
X  	struct timeval	timval;
X  	struct itimerval	ntimer, otimer;
X  	struct tm	*timp;
X! 	int	sectimeout = TIMEOUT;
X! 	char	*ttynam, *ap, *tzn,
X! 		hostname[MAXHOSTNAMELEN],
X! 		s[BUFSIZ], s1[BUFSIZ],
X! 		*crypt(), *index(), *ttyname();
X  
X! 	/* process argument */
X  
X! 	if (argc > 1 && (argv[1][0] != '-' ||
X! 	    (sectimeout = atoi(argv[1] + 1)) <= 0)) {
X! 		puts("Usage: lock [-timeout]");
X! 		exit (1);
X  	}
X  	timeout.tv_sec = sectimeout * 60;
X  
X***************
X*** 82,130 ****
X  
X  	if (ioctl(0, TIOCGETP, &tty))
X  		exit(1);
X- 	pwd = getpwuid(0);
X  	gethostname(hostname, sizeof(hostname));
X! 	if (!(ttynam = ttyname(0))){
X! 		printf("lock: not a terminal?");
X  		exit (1);
X  	}
X! 	gettimeofday(&timval, &timzone);
X  	nexttime = timval.tv_sec + (sectimeout * 60);
X  	timp = localtime(&timval.tv_sec);
X  	ap = asctime(timp);
X! 	tzn = timezone(timzone.tz_minuteswest, timp->tm_isdst);
X  
X  	/* get key and check again */
X  
X! 	signal(SIGINT, quit);
X! 	signal(SIGQUIT, quit);
X  	ntty = tty; ntty.sg_flags &= ~ECHO;
X! 	ioctl(0, TIOCSETN, &ntty);
X! 	printf("Key: ");
X! 	if (fgets(s, sizeof s, stdin) == NULL) {
X! 		putchar('\n');
X  		quit();
X! 	}
X! 	printf("\nAgain: ");
X  	/*
X  	 * Don't need EOF test here, if we get EOF, then s1 != s
X  	 * and the right things will happen.
X  	 */
X! 	(void) fgets(s1, sizeof s1, stdin);
X  	putchar('\n');
X  	if (strcmp(s1, s)) {
X  		putchar(07);
X! 		stty(0, &tty);
X  		exit(1);
X  	}
X! 	s[0] = 0;
X  
X  	/* Set signal handlers */
X  
X! 	signal(SIGINT, hi);
X! 	signal(SIGQUIT, hi);
X! 	signal(SIGTSTP, hi);
X! 	signal(SIGALRM, bye);
X  	ntimer.it_interval = zerotime;
X  	ntimer.it_value = timeout;
X  	setitimer(ITIMER_REAL, &ntimer, &otimer);
X--- 67,118 ----
X  
X  	if (ioctl(0, TIOCGETP, &tty))
X  		exit(1);
X  	gethostname(hostname, sizeof(hostname));
X! 	if (!(ttynam = ttyname(0))) {
X! 		puts("lock: not a terminal?");
X  		exit (1);
X  	}
X! 	if (gettimeofday(&timval, (struct timezone *)NULL)) {
X! 		perror("gettimeofday");
X! 		exit (1);
X! 	}
X  	nexttime = timval.tv_sec + (sectimeout * 60);
X  	timp = localtime(&timval.tv_sec);
X  	ap = asctime(timp);
X! 	tzn = timp->tm_zone;
X  
X  	/* get key and check again */
X  
X! 	(void)signal(SIGINT, quit);
X! 	(void)signal(SIGQUIT, quit);
X  	ntty = tty; ntty.sg_flags &= ~ECHO;
X! 	(void)ioctl(0, TIOCSETP, &ntty);
X! 
X! 	fputs("Key: ",stdout);
X! 	if (!gets(s,sizeof(s)))
X  		quit();
X! 	fputs("\nAgain: ",stdout);
X! 
X  	/*
X  	 * Don't need EOF test here, if we get EOF, then s1 != s
X  	 * and the right things will happen.
X  	 */
X! 	(void)gets(s1,sizeof(s1));
X  	putchar('\n');
X  	if (strcmp(s1, s)) {
X  		putchar(07);
X! 		ioctl(0, TIOCSETP, &tty);
X  		exit(1);
X  	}
X! 	s[0] = NULL;
X  
X  	/* Set signal handlers */
X  
X! 	(void)signal(SIGINT, hi);
X! 	(void)signal(SIGQUIT, hi);
X! 	(void)signal(SIGTSTP, hi);
X! 	(void)signal(SIGALRM, bye);
X! 
X  	ntimer.it_interval = zerotime;
X  	ntimer.it_value = timeout;
X  	setitimer(ITIMER_REAL, &ntimer, &otimer);
X***************
X*** 131,202 ****
X  
X  	/* Header info */
X  
X! 	printf ("lock: %s on %s. timeout in %d minutes\n",
X! 		ttynam, hostname, sectimeout);
X! 	printf("time now is %.20s", ap);
X! 	if (tzn)
X! 		printf("%s", tzn);
X! 	printf("%s", ap+19);
X  
X  	/* wait */
X  
X! 	for (;;) {
X! 		printf("Key: ");
X! 		if (fgets(s, sizeof s, stdin) == NULL) {
X  			clearerr(stdin);
X  			hi();
X  			continue;
X  		}
X! 		if (strcmp(s1, s) == 0)
X  			break;
X! 		if (pwd == (struct passwd *) 0 || pwd->pw_passwd[0] == '\0')
X! 			break;
X! 		ap = index(s, '\n');
X! 		if (ap != NULL)
X! 			*ap = '\0';
X! 		if (strcmp(pwd->pw_passwd, crypt(s, pwd->pw_passwd)) == 0)
X! 			break;
X! 		printf("\07\n");
X  		if (ioctl(0, TIOCGETP, &ntty))
X  			exit(1);
X  	}
X- 	ioctl(0, TIOCSETN, &tty);
X  	putchar('\n');
X! 	exit (0);
X! usage:
X! 	printf("Usage: lock [-timeout]\n");
X! 	exit (1);
X  }
X  
X  /*
X!  *	get out of here
X   */
X  
X! quit()
X  {
X! 	ioctl(0, TIOCSETN, &tty);
X! 	exit (0);
X! }
X  
X! bye()
X! {
X! 	ioctl(0, TIOCSETN, &tty);
X! 	printf("lock: timeout\n");
X! 	exit (1);
X  }
X  
X  /*
X!  *	tell the user we are waiting
X   */
X! 
X! hi()
X  {
X! 	long	curtime;
X! 	struct timeval	timval;
X! 	struct timezone	timzone;
X  
X! 	gettimeofday(&timval, &timzone);
X! 	curtime = timval.tv_sec;
X! 	printf("lock: type in the unlock key. timeout in %d minutes\n",
X! 		(nexttime-curtime)/60);
X  }
X--- 119,175 ----
X  
X  	/* Header info */
X  
X! 	printf ("lock: %s on %s. timeout in %d minutes\ntime now is %.20s%s%s",
X! 		ttynam,hostname,sectimeout,ap,tzn,ap+19);
X  
X  	/* wait */
X  
X! 	for (pwd = getpwuid(0);;) {
X! 		fputs("Key: ",stdout);
X! 		if (!gets(s,sizeof(s))) {
X  			clearerr(stdin);
X  			hi();
X  			continue;
X  		}
X! 		if (!strcmp(s1,s) || !pwd || !*pwd->pw_passwd ||
X! 			!strcmp(pwd->pw_passwd,crypt(s,pwd->pw_passwd)))
X  			break;
X! 		puts("\07");
X  		if (ioctl(0, TIOCGETP, &ntty))
X  			exit(1);
X  	}
X  	putchar('\n');
X! 	quit();
X  }
X  
X  /*
X!  *	tell the user we are waiting
X   */
X  
X! static
X! hi()
X  {
X! 	struct timeval	timval;
X  
X! 	if (!gettimeofday(&timval, (struct timezone *)NULL))
X! 	    printf("lock: type in the unlock key. timeout in %d minutes\n",
X! 	    (nexttime - timval.tv_sec) / 60);
X  }
X  
X  /*
X!  *	get out of here
X   */
X! static
X! quit()
X  {
X! 	(void)ioctl(0, TIOCSETP, &tty);
X! 	exit (0);
X! }
X  
X! static
X! bye()
X! {
X! 	(void)ioctl(0, TIOCSETP, &tty);
X! 	puts("lock: timeout");
X! 	exit (1);
X  }
END-of-diff.lock.c
echo x - diff.main.c
sed 's/^X//' >diff.main.c << 'END-of-diff.main.c'
X*** /nbsd/usr/src/usr.lib/sendmail/src/main.c	Thu Jan 30 11:03:53 1986
X--- main.c	Tue Mar 24 15:30:51 1987
X***************
X*** 132,137 ****
X--- 132,140 ----
X  	}
X  	reenter = TRUE;
X  
X+ 	/* Enforce use of local time */
X+ 	unsetenv("TZ");
X+   
X  	/*
X  	**  Be sure we have enough file descriptors.
X  	*/
END-of-diff.main.c
echo x - diff.time.h
sed 's/^X//' >diff.time.h << 'END-of-diff.time.h'
X*** /nbsd/usr/src/include/time.h	Wed Mar 13 16:30:32 1985
X--- /usr/src/include/time.h	Wed Mar 18 16:23:54 1987
X***************
X*** 1,4 ****
X! /*	time.h	1.1	85/03/13	*/
X  
X  /*
X   * Structure returned by gmtime and localtime calls (see ctime(3)).
X--- 1,10 ----
X! /*
X!  * Copyright (c) 1983, 1987 Regents of the University of California.
X!  * All rights reserved.  The Berkeley software License Agreement
X!  * specifies the terms and conditions for redistribution.
X!  *
X!  *	@(#)time.h	1.2 (Berkeley) 3/4/87
X!  */
X  
X  /*
X   * Structure returned by gmtime and localtime calls (see ctime(3)).
X***************
X*** 13,18 ****
X--- 19,26 ----
X  	int	tm_wday;
X  	int	tm_yday;
X  	int	tm_isdst;
X+ 	long	tm_gmtoff;
X+ 	char	*tm_zone;
X  };
X  
X  extern	struct tm *gmtime(), *localtime();
END-of-diff.time.h
echo x - getenv.3
sed 's/^X//' >getenv.3 << 'END-of-getenv.3'
X.\"	@(#)getenv.3	6.4 (Berkeley) 3/20/87
X.\"
X.TH GETENV 3 "March 20, 1987"
X.AT 3
X.SH NAME
Xgetenv, setenv, unsetenv \- manipulate environmental variables
X.SH SYNOPSIS
X.nf
X.B char *getenv(name)
X.B char *name;
X.PP
X.B setenv(name, value, overwrite)
X.B char *name, value;
X.B int overwrite;
X.PP
X.B void unsetenv(name)
X.B char *name;
X.fi
X.SH DESCRIPTION
X\fIGetenv\fP searches the environment list (see \fIenviron\fP(7))
Xfor a string of the form \fIname\fP\fB=\fP\fIvalue\fP and returns
Xa pointer to the string \fIvalue\fP if such a string is present,
Xand 0 (NULL) if it is not.
X.PP
X\fISetenv\fP searches the environment list as \fIgetenv\fP does; if
Xthe string \fIname\fP is not found, a string of the form
X\fIname\fP\fB=\fP\fIvalue\fP is added to the environment.  If it is
Xfound, and \fIoverwrite\fP is non-zero, its value is changed to
X\fIvalue\fP.  \fISetenv\fP returns 0 on success and -1 on failure,
Xwhere failure is caused by an inability to allocate space for the
Xenvironment.
X.PP
X\fIUnsetenv\fP removes all occurrences of the string \fIname\fP from
Xthe environment.  There is no library provision for completely removing
Xthe current environment.  It is suggested that the following code be
Xused to do so.
X.PP
X.nf
X	static char	*envinit[1];
X	extern char	**environ;
X	environ = envinit;
X.fi
X.PP
XAll of these routines permit, but do not require, a trailing equals
X(``='') sign on \fIname\fP or a leading equals sign on \fIvalue\fP.
X.SH SEE ALSO
Xcsh(1), sh(1), execve(2), environ(7)
END-of-getenv.3
echo x - getenv.c
sed 's/^X//' >getenv.c << 'END-of-getenv.c'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * This file may be freely redistributed provided that this
X * notice remains attached.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)getenv.c	5.4 (Berkeley) 3/13/87";
X#endif LIBC_SCCS and not lint
X
X#include <stdio.h>
X
X/*
X * getenv(name) --
X *	Returns ptr to value associated with name, if any, else NULL.
X */
Xchar *
Xgetenv(name)
X	char *name;
X{
X	int	offset;
X	char	*_findenv();
X
X	return(_findenv(name,&offset));
X}
X
X/*
X * _findenv(name,offset) --
X *	Returns pointer to value associated with name, if any, else NULL.
X *	Sets offset to be the offset of the name/value combination in the
X *	environmental array, for use by setenv(3) and unsetenv(3).
X *	Explicitly removes '=' in argument name.
X *
X *	This routine *should* be a static; don't use it.
X */
Xchar *
X_findenv(name,offset)
X	register char *name;
X	int	*offset;
X{
X	extern char	**environ;
X	register int	len;
X	register char	**P,
X			*C;
X
X	for (C = name,len = 0;*C && *C != '=';++C,++len);
X	for (P = environ;*P;++P)
X		if (!strncmp(*P,name,len))
X			if (*(C = *P + len) == '=') {
X				*offset = P - environ;
X				return(++C);
X			}
X	return(NULL);
X}
END-of-getenv.c
echo x - setenv.c
sed 's/^X//' >setenv.c << 'END-of-setenv.c'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * This file may be freely redistributed provided that this
X * notice remains attached.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)setenv.c	1.2 (Berkeley) 3/13/87";
X#endif LIBC_SCCS and not lint
X
X#include <sys/types.h>
X#include <stdio.h>
X
X/*
X * setenv(name,value,rewrite)
X *	Set the value of the environmental variable "name" to be
X *	"value".  If rewrite is set, replace any current value.
X */
Xsetenv(name,value,rewrite)
X	register char	*name,
X			*value;
X	int	rewrite;
X{
X	extern char	**environ;
X	static int	alloced;		/* if allocated space before */
X	register char	*C;
X	int	l_value,
X		offset;
X	char	*malloc(), *realloc(), *_findenv();
X
X	if (*value == '=')			/* no `=' in value */
X		++value;
X	l_value = strlen(value);
X	if ((C = _findenv(name,&offset))) {	/* find if already exists */
X		if (!rewrite)
X			return(0);
X		if (strlen(C) <= l_value) {	/* smaller; copy over */
X			while (*C++ = *value++);
X			return(0);
X		}
X	}
X	else {					/* create new slot */
X		register int	cnt;
X		register char	**P;
X
X		for (P = environ,cnt = 0;*P;++P,++cnt);
X		if (alloced) {			/* just increase size */
X			environ = (char **)realloc((char *)environ,
X			    (u_int)(sizeof(char *) * (cnt + 2)));
X			if (!environ)
X				return(-1);
X		}
X		else {				/* get new space */
X			alloced = 1;		/* copy old entries into it */
X			P = (char **)malloc((u_int)(sizeof(char *) *
X			    (cnt + 2)));
X			if (!P)
X				return(-1);
X			bcopy(environ,P,cnt * sizeof(char *));
X			environ = P;
X		}
X		environ[cnt + 1] = NULL;
X		offset = cnt;
X	}
X	for (C = name;*C && *C != '=';++C);	/* no `=' in name */
X	if (!(environ[offset] =			/* name + `=' + value */
X	    malloc((u_int)((int)(C - name) + l_value + 2))))
X		return(-1);
X	for (C = environ[offset];(*C = *name++) && *C != '=';++C);
X	for (*C++ = '=';*C++ = *value++;);
X	return(0);
X}
X
X/*
X * unsetenv(name) --
X *	Delete environmental variable "name".
X */
Xvoid
Xunsetenv(name)
X	char	*name;
X{
X	extern	char	**environ;
X	register char	**P;
X	int	offset;
X
X	while (_findenv(name,&offset))		/* if set multiple times */
X		for (P = &environ[offset];;++P)
X			if (!(*P = *(P + 1)))
X				break;
X}
END-of-setenv.c
echo x - timezone.c
sed 's/^X//' >timezone.c << 'END-of-timezone.c'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * This file may be freely redistributed provided that this
X * notice remains attached.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)timezone.c	1.1 (Berkeley) 3/25/87";
X#endif LIBC_SCCS and not lint
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <stdio.h>
X#include <tzfile.h>
X
X/*
X * timezone --
X *	The arguments are the number of minutes of time you are westward
X *	from Greenwich and whether DST is in effect.  It returns a string
X *	giving the name of the local timezone.  Should be replaced, in the
X *	application code, by a call to localtime.
X */
X
Xstatic char	czone[TZ_MAX_CHARS];		/* space for zone name */
X
Xchar *
Xtimezone(zone, dst)
X	int	zone,
X		dst;
X{
X	register char	*beg,
X			*end;
X	char	*getenv(), *index(), *strncpy(), *tztab();
X
X	if (beg = getenv("TZNAME")) {		/* set in environment */
X		if (end = index(beg, ',')) {	/* "PST,PDT" */
X			if (dst)
X				return(++end);
X			*end = '\0';
X			(void)strncpy(czone,beg,sizeof(czone) - 1);
X			czone[sizeof(czone) - 1] = '\0';
X			*end = ',';
X			return(czone);
X		}
X		return(beg);
X	}
X	return(tztab(zone,dst));	/* default: table or created zone */
X}
X
Xstatic struct zone {
X	int	offset;
X	char	*stdzone;
X	char	*dlzone;
X} zonetab[] = {
X	-1*60,	"MET",	"MET DST",	/* Middle European */
X	-2*60,	"EET",	"EET DST",	/* Eastern European */
X	4*60,	"AST",	"ADT",		/* Atlantic */
X	5*60,	"EST",	"EDT",		/* Eastern */
X	6*60,	"CST",	"CDT",		/* Central */
X	7*60,	"MST",	"MDT",		/* Mountain */
X	8*60,	"PST",	"PDT",		/* Pacific */
X#ifdef notdef
X	/* there's no way to distinguish this from WET */
X	0,	"GMT",	0,		/* Greenwich */
X#endif
X	0*60,	"WET",	"WET DST",	/* Western European */
X	-10*60,	"EST",	"EST",		/* Aust: Eastern */
X     -10*60+30,	"CST",	"CST",		/* Aust: Central */
X	-8*60,	"WST",	0,		/* Aust: Western */
X	-1
X};
X
X/*
X * tztab --
X *	check static tables or create a new zone name; broken out so that
X *	we can make a guess as to what the zone is if the standard tables
X *	aren't in place in /etc.  DO NOT USE THIS ROUTINE OUTSIDE OF THE
X *	STANDARD LIBRARY.
X */
Xchar *
Xtztab(zone,dst)
X	register int	zone;
X	int	dst;
X{
X	register struct zone	*zp;
X	register char	sign;
X
X	for (zp = zonetab; zp->offset != -1;++zp)	/* static tables */
X		if (zp->offset == zone) {
X			if (dst && zp->dlzone)
X				return(zp->dlzone);
X			if (!dst && zp->stdzone)
X				return(zp->stdzone);
X		}
X
X	if (zone < 0) {					/* create one */
X		zone = -zone;
X		sign = '+';
X	}
X	else
X		sign = '-';
X	(void)sprintf(czone,"GMT%c%d:%02d",sign,zone / 60,zone % 60);
X	return(czone);
X}
END-of-timezone.c
echo x - tzfile.5
sed 's/^X//' >tzfile.5 << 'END-of-tzfile.5'
X.\"	@(#)tzfile.5	1.2 (Berkeley) 3/11/87
X.\"
X.TH TZFILE 5
X.AT 5
X.SH NAME
Xtzfile \- time zone information
X.SH SYNOPSIS
X.B
X#include <tzfile.h>
X.SH DESCRIPTION
XThe time zone information files used by
X.IR tzset (3)
Xbegin with bytes reserved for future use,
Xfollowed by three four-byte values of type
X.BR long ,
Xwritten in a ``standard'' byte order
X(the high-order byte of the value is written first).
XThese values are,
Xin order:
X.TP
X.I tzh_timecnt
XThe number of "transition times" for which data is stored
Xin the file.
X.TP
X.I tzh_typecnt
XThe number of "local time types" for which data is stored
Xin the file (must not be zero).
X.TP
X.I tzh_charcnt
XThe number of characters of "time zone abbreviation strings"
Xstored in the file.
X.PP
XThe above header is followed by
X.I tzh_timecnt
Xfour-byte values of type
X.BR long ,
Xsorted in ascending order.
XThese values are written in ``standard'' byte order.
XEach is used as a transition time (as returned by
X.IR time (2))
Xat which the rules for computing local time change.
XNext come
X.I tzh_timecnt
Xone-byte values of type
X.BR "unsigned char" ;
Xeach one tells which of the different types of ``local time'' types
Xdescribed in the file is associated with the same-indexed transition time.
XThese values serve as indices into an array of
X.I ttinfo
Xstructures that appears next in the file; 
Xthese structures are defined as follows:
X.in +.5i
X.sp
X.nf
X.ta .5i +\w'unsigned int\0\0'u
Xstruct ttinfo {	
X	long	tt_gmtoff;
X	int	tt_isdst;
X	unsigned int	tt_abbrind;
X};
X.in -.5i
X.fi
X.sp
XEach structure is written as a four-byte value for
X.I tt_gmtoff
Xof type
X.BR long ,
Xin a standard byte order, followed by a one-byte value for
X.I tt_isdst
Xand a one-byte value for
X.IR tt_abbrind .
XIn each structure,
X.I tt_gmtoff
Xgives the number of seconds to be added to GMT,
X.I tt_isdst
Xtells whether
X.I tm_isdst
Xshould be set by
X.I localtime (3)
Xand
X.I tt_abbrind
Xserves as an index into the array of time zone abbreviation characters
Xthat follow the
X.I ttinfo
Xstructure(s) in the file.
X.PP
X.I Localtime
Xuses the first standard-time
X.I ttinfo
Xstructure in the file
X(or simply the first
X.I ttinfo
Xstructure in the absence of a standard-time structure)
Xif either
X.I tzh_timecnt
Xis zero or the time argument is less than the first transition time recorded
Xin the file.
X.SH SEE ALSO
Xctime(3)
END-of-tzfile.5
echo x - tzfile.h
sed 's/^X//' >tzfile.h << 'END-of-tzfile.h'
X/*
X *	@(#)tzfile.h	5.2 tzfile.h 3/4/87
X */
X
X/*
X** Information about time zone files.
X*/
X
X#define	TZDIR		"/etc/zoneinfo"	/* Time zone object file directory */
X#define	TZDEFAULT	"localtime"
X
X/*
X** Each file begins with. . .
X*/
X
Xstruct tzhead {
X	char	tzh_reserved[32];	/* reserved for future use */
X	char	tzh_timecnt[4];		/* coded number of transition times */
X	char	tzh_typecnt[4];		/* coded number of local time types */
X	char	tzh_charcnt[4];		/* coded number of abbr. chars */
X};
X
X/*
X** . . .followed by. . .
X**
X**	tzh_timecnt (char [4])s		coded transition times a la time(2)
X**	tzh_timecnt (unsigned char)s	types of local time starting at above
X**	tzh_typecnt repetitions of
X**		one (char [4])		coded GMT offset in seconds
X**		one (unsigned char)	used to set tm_isdt
X**		one (unsigned char)	that's an abbreviation list index
X**	tzh_charcnt (char)s		'\0'-terminated zone abbreviaton strings
X*/
X
X/*
X** In the current implementation, "tzset()" refuses to deal with files that
X** exceed any of the limits below.
X*/
X
X/*
X** The TZ_MAX_TIMES value below is enough to handle a bit more than a
X** year's worth of solar time (corrected daily to the nearest second) or
X** 138 years of Pacific Presidential Election time
X** (where there are three time zone transitions every fourth year).
X*/
X#define	TZ_MAX_TIMES	370
X
X#define	NOSOLAR			/* We currently don't handle solar time */
X
X#ifndef	NOSOLAR
X#define	TZ_MAX_TYPES	256	/* Limited by what (unsigned char)'s can hold */
X#else /* !NOSOLAR */
X#define	TZ_MAX_TYPES	10	/* Maximum number of local time types */
X#endif /* !NOSOLAR */
X
X#define	TZ_MAX_CHARS	50	/* Maximum number of abbreviation characters */
X
X#define	SECS_PER_MIN	60
X#define	MINS_PER_HOUR	60
X#define	HOURS_PER_DAY	24
X#define	DAYS_PER_WEEK	7
X#define	DAYS_PER_NYEAR	365
X#define	DAYS_PER_LYEAR	366
X#define	SECS_PER_HOUR	(SECS_PER_MIN * MINS_PER_HOUR)
X#define	SECS_PER_DAY	((long) SECS_PER_HOUR * HOURS_PER_DAY)
X#define	MONS_PER_YEAR	12
X
X#define	TM_SUNDAY	0
X#define	TM_MONDAY	1
X#define	TM_TUESDAY	2
X#define	TM_WEDNESDAY	3
X#define	TM_THURSDAY	4
X#define	TM_FRIDAY	5
X#define	TM_SATURDAY	6
X
X#define	TM_JANUARY	0
X#define	TM_FEBRUARY	1
X#define	TM_MARCH	2
X#define	TM_APRIL	3
X#define	TM_MAY		4
X#define	TM_JUNE		5
X#define	TM_JULY		6
X#define	TM_AUGUST	7
X#define	TM_SEPTEMBER	8
X#define	TM_OCTOBER	9
X#define	TM_NOVEMBER	10
X#define	TM_DECEMBER	11
X#define	TM_SUNDAY	0
X
X#define	TM_YEAR_BASE	1900
X
X#define	EPOCH_YEAR	1970
X#define	EPOCH_WDAY	TM_THURSDAY
X
X/*
X** Accurate only for the past couple of centuries;
X** that will probably do.
X*/
X
X#define	isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
END-of-tzfile.h
exit