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 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 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 * 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 * 146 localtime(const time_t *clock) 147 { 148 return (gmtime(clock)); 149 } 150 151 static char * 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 * 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 * 208 ctime(const time_t *t) 209 { 210 return (asctime(localtime(t))); 211 } 212