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