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", §imeout) != 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