1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate *
26*0Sstevel@tonic-gate * Time routines, snagged from libc.
27*0Sstevel@tonic-gate */
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gate #include <errno.h>
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/bootvfs.h>
34*0Sstevel@tonic-gate #include <sys/salib.h>
35*0Sstevel@tonic-gate #include <sys/promif.h>
36*0Sstevel@tonic-gate #include <stdio.h>
37*0Sstevel@tonic-gate #include <time.h>
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gate #define CBUFSIZ 26
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate static time_t start_time, secs_since_boot;
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gate const int __year_lengths[2] = {
44*0Sstevel@tonic-gate DAYS_PER_NYEAR, DAYS_PER_LYEAR
45*0Sstevel@tonic-gate };
46*0Sstevel@tonic-gate const int __mon_lengths[2][MONS_PER_YEAR] = {
47*0Sstevel@tonic-gate 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
48*0Sstevel@tonic-gate 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
49*0Sstevel@tonic-gate };
50*0Sstevel@tonic-gate
51*0Sstevel@tonic-gate /*
52*0Sstevel@tonic-gate * Initializes our "clock" to the creation date of /timestamp, which is
53*0Sstevel@tonic-gate * made on the fly for us by the web server. Thereafter, time() will keep
54*0Sstevel@tonic-gate * time sort of up to date.
55*0Sstevel@tonic-gate */
56*0Sstevel@tonic-gate void
init_boot_time(void)57*0Sstevel@tonic-gate init_boot_time(void)
58*0Sstevel@tonic-gate {
59*0Sstevel@tonic-gate struct stat sb;
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gate if (start_time == 0) {
62*0Sstevel@tonic-gate if (stat("/timestamp", &sb) < 0)
63*0Sstevel@tonic-gate prom_panic("init_boot_time: cannot stat /timestamp");
64*0Sstevel@tonic-gate
65*0Sstevel@tonic-gate start_time = sb.st_ctim.tv_sec;
66*0Sstevel@tonic-gate secs_since_boot = prom_gettime() / 1000;
67*0Sstevel@tonic-gate }
68*0Sstevel@tonic-gate }
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gate /*
71*0Sstevel@tonic-gate * Time is crudely incremented.
72*0Sstevel@tonic-gate */
73*0Sstevel@tonic-gate time_t
time(time_t * tloc)74*0Sstevel@tonic-gate time(time_t *tloc)
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate time_t time_now;
77*0Sstevel@tonic-gate
78*0Sstevel@tonic-gate time_now = start_time + ((prom_gettime() / 1000) - secs_since_boot);
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gate if (tloc != NULL)
81*0Sstevel@tonic-gate *tloc = time_now;
82*0Sstevel@tonic-gate
83*0Sstevel@tonic-gate if (start_time == 0)
84*0Sstevel@tonic-gate return (0);
85*0Sstevel@tonic-gate else
86*0Sstevel@tonic-gate return (time_now);
87*0Sstevel@tonic-gate }
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate struct tm *
gmtime(const time_t * clock)90*0Sstevel@tonic-gate gmtime(const time_t *clock)
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate static struct tm result;
93*0Sstevel@tonic-gate struct tm *tmp;
94*0Sstevel@tonic-gate long days;
95*0Sstevel@tonic-gate int rem;
96*0Sstevel@tonic-gate long y;
97*0Sstevel@tonic-gate long newy;
98*0Sstevel@tonic-gate const int *ip;
99*0Sstevel@tonic-gate
100*0Sstevel@tonic-gate tmp = &result;
101*0Sstevel@tonic-gate days = *clock / SECS_PER_DAY;
102*0Sstevel@tonic-gate rem = *clock % SECS_PER_DAY;
103*0Sstevel@tonic-gate while (rem < 0) {
104*0Sstevel@tonic-gate rem += SECS_PER_DAY;
105*0Sstevel@tonic-gate --days;
106*0Sstevel@tonic-gate }
107*0Sstevel@tonic-gate while (rem >= SECS_PER_DAY) {
108*0Sstevel@tonic-gate rem -= SECS_PER_DAY;
109*0Sstevel@tonic-gate ++days;
110*0Sstevel@tonic-gate }
111*0Sstevel@tonic-gate tmp->tm_hour = (int)(rem / SECS_PER_HOUR);
112*0Sstevel@tonic-gate rem = rem % SECS_PER_HOUR;
113*0Sstevel@tonic-gate tmp->tm_min = (int)(rem / SECS_PER_MIN);
114*0Sstevel@tonic-gate tmp->tm_sec = (int)(rem % SECS_PER_MIN);
115*0Sstevel@tonic-gate tmp->tm_wday = (int)((EPOCH_WDAY + days) % DAYS_PER_WEEK);
116*0Sstevel@tonic-gate if (tmp->tm_wday < 0)
117*0Sstevel@tonic-gate tmp->tm_wday += DAYS_PER_WEEK;
118*0Sstevel@tonic-gate y = EPOCH_YEAR;
119*0Sstevel@tonic-gate
120*0Sstevel@tonic-gate #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
121*0Sstevel@tonic-gate
122*0Sstevel@tonic-gate while (days < 0 || days >= (long)__year_lengths[isleap(y)]) {
123*0Sstevel@tonic-gate newy = y + days / DAYS_PER_NYEAR;
124*0Sstevel@tonic-gate if (days < 0)
125*0Sstevel@tonic-gate --newy;
126*0Sstevel@tonic-gate days -= ((long)newy - (long)y) * DAYS_PER_NYEAR +
127*0Sstevel@tonic-gate LEAPS_THRU_END_OF(newy > 0 ? newy - 1L : newy) -
128*0Sstevel@tonic-gate LEAPS_THRU_END_OF(y > 0 ? y - 1L : y);
129*0Sstevel@tonic-gate y = newy;
130*0Sstevel@tonic-gate }
131*0Sstevel@tonic-gate
132*0Sstevel@tonic-gate tmp->tm_year = y - TM_YEAR_BASE;
133*0Sstevel@tonic-gate tmp->tm_yday = days;
134*0Sstevel@tonic-gate ip = __mon_lengths[isleap(y)];
135*0Sstevel@tonic-gate for (tmp->tm_mon = 0; days >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
136*0Sstevel@tonic-gate days = days - ip[tmp->tm_mon];
137*0Sstevel@tonic-gate tmp->tm_mday = (days + 1);
138*0Sstevel@tonic-gate tmp->tm_isdst = 0;
139*0Sstevel@tonic-gate return (tmp);
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate
142*0Sstevel@tonic-gate /*
143*0Sstevel@tonic-gate * The standalone booter runs in GMT.
144*0Sstevel@tonic-gate */
145*0Sstevel@tonic-gate struct tm *
localtime(const time_t * clock)146*0Sstevel@tonic-gate localtime(const time_t *clock)
147*0Sstevel@tonic-gate {
148*0Sstevel@tonic-gate return (gmtime(clock));
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate static char *
ct_numb(char * cp,int n)152*0Sstevel@tonic-gate ct_numb(char *cp, int n)
153*0Sstevel@tonic-gate {
154*0Sstevel@tonic-gate cp++;
155*0Sstevel@tonic-gate if (n >= 10)
156*0Sstevel@tonic-gate *cp++ = (n / 10) % 10 + '0';
157*0Sstevel@tonic-gate else
158*0Sstevel@tonic-gate *cp++ = ' '; /* Pad with blanks */
159*0Sstevel@tonic-gate *cp++ = n % 10 + '0';
160*0Sstevel@tonic-gate return (cp);
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate char *
asctime(const struct tm * t)164*0Sstevel@tonic-gate asctime(const struct tm *t)
165*0Sstevel@tonic-gate {
166*0Sstevel@tonic-gate char *cp;
167*0Sstevel@tonic-gate const char *ncp;
168*0Sstevel@tonic-gate const int *tp;
169*0Sstevel@tonic-gate const char *Date = "Day Mon 00 00:00:00 1900\n";
170*0Sstevel@tonic-gate const char *Day = "SunMonTueWedThuFriSat";
171*0Sstevel@tonic-gate const char *Month = "JanFebMarAprMayJunJulAugSepOctNovDec";
172*0Sstevel@tonic-gate static char cbuf[CBUFSIZ];
173*0Sstevel@tonic-gate
174*0Sstevel@tonic-gate cp = cbuf;
175*0Sstevel@tonic-gate for (ncp = Date; *cp++ = *ncp++; /* */);
176*0Sstevel@tonic-gate ncp = Day + (3 * t->tm_wday);
177*0Sstevel@tonic-gate cp = cbuf;
178*0Sstevel@tonic-gate *cp++ = *ncp++;
179*0Sstevel@tonic-gate *cp++ = *ncp++;
180*0Sstevel@tonic-gate *cp++ = *ncp++;
181*0Sstevel@tonic-gate cp++;
182*0Sstevel@tonic-gate tp = &t->tm_mon;
183*0Sstevel@tonic-gate ncp = Month + ((*tp) * 3);
184*0Sstevel@tonic-gate *cp++ = *ncp++;
185*0Sstevel@tonic-gate *cp++ = *ncp++;
186*0Sstevel@tonic-gate *cp++ = *ncp++;
187*0Sstevel@tonic-gate cp = ct_numb(cp, *--tp);
188*0Sstevel@tonic-gate cp = ct_numb(cp, *--tp + 100);
189*0Sstevel@tonic-gate cp = ct_numb(cp, *--tp + 100);
190*0Sstevel@tonic-gate --tp;
191*0Sstevel@tonic-gate cp = ct_numb(cp, *tp + 100);
192*0Sstevel@tonic-gate if (t->tm_year < 100) {
193*0Sstevel@tonic-gate /* Common case: "19" already in buffer */
194*0Sstevel@tonic-gate cp += 2;
195*0Sstevel@tonic-gate } else if (t->tm_year < 8100) {
196*0Sstevel@tonic-gate cp = ct_numb(cp, (1900 + t->tm_year) / 100);
197*0Sstevel@tonic-gate cp--;
198*0Sstevel@tonic-gate } else {
199*0Sstevel@tonic-gate /* Only 4-digit years are supported */
200*0Sstevel@tonic-gate errno = EOVERFLOW;
201*0Sstevel@tonic-gate return (NULL);
202*0Sstevel@tonic-gate }
203*0Sstevel@tonic-gate (void) ct_numb(cp, t->tm_year + 100);
204*0Sstevel@tonic-gate return (cbuf);
205*0Sstevel@tonic-gate }
206*0Sstevel@tonic-gate
207*0Sstevel@tonic-gate char *
ctime(const time_t * t)208*0Sstevel@tonic-gate ctime(const time_t *t)
209*0Sstevel@tonic-gate {
210*0Sstevel@tonic-gate return (asctime(localtime(t)));
211*0Sstevel@tonic-gate }
212