Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/DateConstants.h>
8#include <AK/DeprecatedString.h>
9#include <AK/StringBuilder.h>
10#include <AK/Time.h>
11#include <Kernel/API/TimePage.h>
12#include <LibTimeZone/TimeZone.h>
13#include <assert.h>
14#include <bits/pthread_cancel.h>
15#include <errno.h>
16#include <limits.h>
17#include <stdio.h>
18#include <string.h>
19#include <sys/time.h>
20#include <sys/times.h>
21#include <syscall.h>
22#include <time.h>
23#include <utime.h>
24
25extern "C" {
26
27static constexpr char const* __utc = "UTC";
28static StringView __tzname { __utc, __builtin_strlen(__utc) };
29static char __tzname_standard[TZNAME_MAX];
30static char __tzname_daylight[TZNAME_MAX];
31
32long timezone = 0;
33long altzone = 0;
34char* tzname[2] = { const_cast<char*>(__utc), const_cast<char*>(__utc) };
35int daylight = 0;
36
37time_t time(time_t* tloc)
38{
39 struct timeval tv;
40 struct timezone tz;
41 if (gettimeofday(&tv, &tz) < 0)
42 return (time_t)-1;
43 if (tloc)
44 *tloc = tv.tv_sec;
45 return tv.tv_sec;
46}
47
48int adjtime(const struct timeval* delta, struct timeval* old_delta)
49{
50 int rc = syscall(SC_adjtime, delta, old_delta);
51 __RETURN_WITH_ERRNO(rc, rc, -1);
52}
53
54int gettimeofday(struct timeval* __restrict__ tv, void* __restrict__)
55{
56 if (!tv) {
57 errno = EFAULT;
58 return -1;
59 }
60
61 struct timespec ts = {};
62 if (clock_gettime(CLOCK_REALTIME_COARSE, &ts) < 0)
63 return -1;
64
65 TIMESPEC_TO_TIMEVAL(tv, &ts);
66 return 0;
67}
68
69int settimeofday(struct timeval* __restrict__ tv, void* __restrict__)
70{
71 if (!tv) {
72 errno = EFAULT;
73 return -1;
74 }
75
76 timespec ts;
77 TIMEVAL_TO_TIMESPEC(tv, &ts);
78 return clock_settime(CLOCK_REALTIME, &ts);
79}
80
81int utimes(char const* pathname, const struct timeval times[2])
82{
83 if (!times) {
84 return utime(pathname, nullptr);
85 }
86 // FIXME: implement support for tv_usec in the utime (or a new) syscall
87 utimbuf buf = { times[0].tv_sec, times[1].tv_sec };
88 return utime(pathname, &buf);
89}
90
91char* ctime(time_t const* t)
92{
93 return asctime(localtime(t));
94}
95
96char* ctime_r(time_t const* t, char* buf)
97{
98 struct tm tm_buf;
99 return asctime_r(localtime_r(t, &tm_buf), buf);
100}
101
102static int const __seconds_per_day = 60 * 60 * 24;
103
104static bool is_valid_time(time_t timestamp)
105{
106 // Note: these correspond to the number of seconds from epoch to the dates "Jan 1 00:00:00 -2147483648" and "Dec 31 23:59:59 2147483647",
107 // respectively, which are the smallest and biggest representable dates without overflowing tm->tm_year, if it is an int.
108 constexpr time_t smallest_possible_time = -67768040609740800;
109 constexpr time_t biggest_possible_time = 67768036191676799;
110
111 return (timestamp >= smallest_possible_time) && (timestamp <= biggest_possible_time);
112}
113
114static struct tm* time_to_tm(struct tm* tm, time_t t, StringView time_zone)
115{
116 if (!is_valid_time(t)) {
117 errno = EOVERFLOW;
118 return nullptr;
119 }
120
121 if (auto offset = TimeZone::get_time_zone_offset(time_zone, AK::Time::from_seconds(t)); offset.has_value()) {
122 tm->tm_isdst = offset->in_dst == TimeZone::InDST::Yes;
123 t += offset->seconds;
124 }
125
126 int year = 1970;
127 for (; t >= days_in_year(year) * __seconds_per_day; ++year)
128 t -= days_in_year(year) * __seconds_per_day;
129 for (; t < 0; --year)
130 t += days_in_year(year - 1) * __seconds_per_day;
131 tm->tm_year = year - 1900;
132
133 VERIFY(t >= 0);
134 int days = t / __seconds_per_day;
135 tm->tm_yday = days;
136 int remaining = t % __seconds_per_day;
137 tm->tm_sec = remaining % 60;
138 remaining /= 60;
139 tm->tm_min = remaining % 60;
140 tm->tm_hour = remaining / 60;
141
142 int month;
143 for (month = 1; month < 12 && days >= days_in_month(year, month); ++month)
144 days -= days_in_month(year, month);
145
146 tm->tm_mday = days + 1;
147 tm->tm_wday = day_of_week(year, month, tm->tm_mday);
148 tm->tm_mon = month - 1;
149
150 return tm;
151}
152
153static time_t tm_to_time(struct tm* tm, StringView time_zone)
154{
155 // "The original values of the tm_wday and tm_yday components of the structure are ignored,
156 // and the original values of the other components are not restricted to the ranges described in <time.h>.
157 // [...]
158 // Upon successful completion, the values of the tm_wday and tm_yday components of the structure shall be set appropriately,
159 // and the other components are set to represent the specified time since the Epoch,
160 // but with their values forced to the ranges indicated in the <time.h> entry;
161 // the final value of tm_mday shall not be set until tm_mon and tm_year are determined."
162
163 tm->tm_year += tm->tm_mon / 12;
164 tm->tm_mon %= 12;
165 if (tm->tm_mon < 0) {
166 tm->tm_year--;
167 tm->tm_mon += 12;
168 }
169
170 tm->tm_yday = day_of_year(1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
171 time_t days_since_epoch = years_to_days_since_epoch(1900 + tm->tm_year) + tm->tm_yday;
172 auto timestamp = ((days_since_epoch * 24 + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
173
174 if (tm->tm_isdst < 0) {
175 if (auto offset = TimeZone::get_time_zone_offset(time_zone, AK::Time::from_seconds(timestamp)); offset.has_value())
176 timestamp -= offset->seconds;
177 } else {
178 auto index = tm->tm_isdst == 0 ? 0 : 1;
179
180 if (auto offsets = TimeZone::get_named_time_zone_offsets(time_zone, AK::Time::from_seconds(timestamp)); offsets.has_value())
181 timestamp -= offsets->at(index).seconds;
182 }
183
184 if (!is_valid_time(timestamp)) {
185 errno = EOVERFLOW;
186 return -1;
187 }
188
189 return timestamp;
190}
191
192time_t mktime(struct tm* tm)
193{
194 tzset();
195 return tm_to_time(tm, __tzname);
196}
197
198struct tm* localtime(time_t const* t)
199{
200 tzset();
201
202 static struct tm tm_buf;
203 return localtime_r(t, &tm_buf);
204}
205
206struct tm* localtime_r(time_t const* t, struct tm* tm)
207{
208 if (!t)
209 return nullptr;
210
211 return time_to_tm(tm, *t, __tzname);
212}
213
214time_t timegm(struct tm* tm)
215{
216 tm->tm_isdst = 0;
217 return tm_to_time(tm, { __utc, __builtin_strlen(__utc) });
218}
219
220struct tm* gmtime(time_t const* t)
221{
222 static struct tm tm_buf;
223 return gmtime_r(t, &tm_buf);
224}
225
226struct tm* gmtime_r(time_t const* t, struct tm* tm)
227{
228 if (!t)
229 return nullptr;
230 return time_to_tm(tm, *t, { __utc, __builtin_strlen(__utc) });
231}
232
233char* asctime(const struct tm* tm)
234{
235 static char buffer[69];
236 return asctime_r(tm, buffer);
237}
238
239char* asctime_r(const struct tm* tm, char* buffer)
240{
241 // Spec states buffer must be at least 26 bytes.
242 constexpr size_t assumed_len = 26;
243 size_t filled_size = strftime(buffer, assumed_len, "%a %b %e %T %Y\n", tm);
244
245 // If the buffer was not large enough, set EOVERFLOW and return null.
246 if (filled_size == 0) {
247 errno = EOVERFLOW;
248 return nullptr;
249 }
250
251 return buffer;
252}
253
254// FIXME: Some formats are not supported.
255size_t strftime(char* destination, size_t max_size, char const* format, const struct tm* tm)
256{
257 tzset();
258
259 StringBuilder builder { max_size };
260
261 int const format_len = strlen(format);
262 for (int i = 0; i < format_len; ++i) {
263 if (format[i] != '%') {
264 builder.append(format[i]);
265 } else {
266 if (++i >= format_len)
267 return 0;
268
269 switch (format[i]) {
270 case 'a':
271 builder.append(short_day_names[tm->tm_wday]);
272 break;
273 case 'A':
274 builder.append(long_day_names[tm->tm_wday]);
275 break;
276 case 'b':
277 builder.append(short_month_names[tm->tm_mon]);
278 break;
279 case 'B':
280 builder.append(long_month_names[tm->tm_mon]);
281 break;
282 case 'C':
283 builder.appendff("{:02}", (tm->tm_year + 1900) / 100);
284 break;
285 case 'd':
286 builder.appendff("{:02}", tm->tm_mday);
287 break;
288 case 'D':
289 builder.appendff("{:02}/{:02}/{:02}", tm->tm_mon + 1, tm->tm_mday, (tm->tm_year + 1900) % 100);
290 break;
291 case 'e':
292 builder.appendff("{:2}", tm->tm_mday);
293 break;
294 case 'h':
295 builder.append(short_month_names[tm->tm_mon]);
296 break;
297 case 'H':
298 builder.appendff("{:02}", tm->tm_hour);
299 break;
300 case 'I': {
301 int display_hour = tm->tm_hour % 12;
302 if (display_hour == 0)
303 display_hour = 12;
304 builder.appendff("{:02}", display_hour);
305 break;
306 }
307 case 'j':
308 builder.appendff("{:03}", tm->tm_yday + 1);
309 break;
310 case 'm':
311 builder.appendff("{:02}", tm->tm_mon + 1);
312 break;
313 case 'M':
314 builder.appendff("{:02}", tm->tm_min);
315 break;
316 case 'n':
317 builder.append('\n');
318 break;
319 case 'p':
320 builder.append(tm->tm_hour < 12 ? "AM"sv : "PM"sv);
321 break;
322 case 'r': {
323 int display_hour = tm->tm_hour % 12;
324 if (display_hour == 0)
325 display_hour = 12;
326 builder.appendff("{:02}:{:02}:{:02} {}", display_hour, tm->tm_min, tm->tm_sec, tm->tm_hour < 12 ? "AM" : "PM");
327 break;
328 }
329 case 'R':
330 builder.appendff("{:02}:{:02}", tm->tm_hour, tm->tm_min);
331 break;
332 case 'S':
333 builder.appendff("{:02}", tm->tm_sec);
334 break;
335 case 't':
336 builder.append('\t');
337 break;
338 case 'T':
339 builder.appendff("{:02}:{:02}:{:02}", tm->tm_hour, tm->tm_min, tm->tm_sec);
340 break;
341 case 'u':
342 builder.appendff("{}", tm->tm_wday ? tm->tm_wday : 7);
343 break;
344 case 'U': {
345 int const wday_of_year_beginning = (tm->tm_wday + 6 * tm->tm_yday) % 7;
346 int const week_number = (tm->tm_yday + wday_of_year_beginning) / 7;
347 builder.appendff("{:02}", week_number);
348 break;
349 }
350 case 'V': {
351 int const wday_of_year_beginning = (tm->tm_wday + 6 + 6 * tm->tm_yday) % 7;
352 int week_number = (tm->tm_yday + wday_of_year_beginning) / 7 + 1;
353 if (wday_of_year_beginning > 3) {
354 if (tm->tm_yday >= 7 - wday_of_year_beginning)
355 --week_number;
356 else {
357 int const days_of_last_year = days_in_year(tm->tm_year + 1900 - 1);
358 int const wday_of_last_year_beginning = (wday_of_year_beginning + 6 * days_of_last_year) % 7;
359 week_number = (days_of_last_year + wday_of_last_year_beginning) / 7 + 1;
360 if (wday_of_last_year_beginning > 3)
361 --week_number;
362 }
363 }
364 builder.appendff("{:02}", week_number);
365 break;
366 }
367 case 'w':
368 builder.appendff("{}", tm->tm_wday);
369 break;
370 case 'W': {
371 int const wday_of_year_beginning = (tm->tm_wday + 6 + 6 * tm->tm_yday) % 7;
372 int const week_number = (tm->tm_yday + wday_of_year_beginning) / 7;
373 builder.appendff("{:02}", week_number);
374 break;
375 }
376 case 'y':
377 builder.appendff("{:02}", (tm->tm_year + 1900) % 100);
378 break;
379 case 'Y':
380 builder.appendff("{}", tm->tm_year + 1900);
381 break;
382 case '%':
383 builder.append('%');
384 break;
385 default:
386 return 0;
387 }
388 }
389 if (builder.length() + 1 > max_size)
390 return 0;
391 }
392
393 auto str = builder.to_deprecated_string();
394 bool fits = str.copy_characters_to_buffer(destination, max_size);
395 return fits ? str.length() : 0;
396}
397
398void tzset()
399{
400 __tzname = TimeZone::current_time_zone();
401
402 auto set_default_values = []() {
403 timezone = 0;
404 altzone = 0;
405 daylight = 0;
406 __tzname = StringView { __utc, __builtin_strlen(__utc) };
407 tzname[0] = const_cast<char*>(__utc);
408 tzname[1] = const_cast<char*>(__utc);
409 };
410
411 if (auto offsets = TimeZone::get_named_time_zone_offsets(__tzname, AK::Time::now_realtime()); offsets.has_value()) {
412 if (!offsets->at(0).name.copy_characters_to_buffer(__tzname_standard, TZNAME_MAX))
413 return set_default_values();
414 if (!offsets->at(1).name.copy_characters_to_buffer(__tzname_daylight, TZNAME_MAX))
415 return set_default_values();
416
417 // timezone and altzone are seconds west of UTC, i.e. the offsets are negated.
418 timezone = -offsets->at(0).seconds;
419 altzone = -offsets->at(1).seconds;
420 daylight = timezone != altzone;
421 tzname[0] = __tzname_standard;
422 tzname[1] = __tzname_daylight;
423 } else {
424 set_default_values();
425 }
426}
427
428clock_t clock()
429{
430 struct tms tms;
431 times(&tms);
432 return tms.tms_utime + tms.tms_stime;
433}
434
435static Kernel::TimePage* get_kernel_time_page()
436{
437 static Kernel::TimePage* s_kernel_time_page;
438 // FIXME: Thread safety
439 if (!s_kernel_time_page) {
440 auto rc = syscall(SC_map_time_page);
441 if ((int)rc < 0 && (int)rc > -EMAXERRNO) {
442 errno = -(int)rc;
443 return nullptr;
444 }
445 s_kernel_time_page = (Kernel::TimePage*)rc;
446 }
447 return s_kernel_time_page;
448}
449
450int clock_gettime(clockid_t clock_id, struct timespec* ts)
451{
452 if (Kernel::time_page_supports(clock_id)) {
453 if (!ts) {
454 errno = EFAULT;
455 return -1;
456 }
457
458 if (auto* kernel_time_page = get_kernel_time_page()) {
459 u32 update_iteration;
460 do {
461 update_iteration = AK::atomic_load(&kernel_time_page->update1, AK::memory_order_acquire);
462 *ts = kernel_time_page->clocks[clock_id];
463 } while (update_iteration != AK::atomic_load(&kernel_time_page->update2, AK::memory_order_acquire));
464 return 0;
465 }
466 }
467
468 int rc = syscall(SC_clock_gettime, clock_id, ts);
469 __RETURN_WITH_ERRNO(rc, rc, -1);
470}
471
472int clock_settime(clockid_t clock_id, struct timespec* ts)
473{
474 int rc = syscall(SC_clock_settime, clock_id, ts);
475 __RETURN_WITH_ERRNO(rc, rc, -1);
476}
477
478int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec* requested_sleep, struct timespec* remaining_sleep)
479{
480 __pthread_maybe_cancel();
481
482 Syscall::SC_clock_nanosleep_params params { clock_id, flags, requested_sleep, remaining_sleep };
483 int rc = syscall(SC_clock_nanosleep, ¶ms);
484 __RETURN_WITH_ERRNO(rc, rc, -1);
485}
486
487int nanosleep(const struct timespec* requested_sleep, struct timespec* remaining_sleep)
488{
489 return clock_nanosleep(CLOCK_REALTIME, 0, requested_sleep, remaining_sleep);
490}
491
492int clock_getres(clockid_t clock_id, struct timespec* result)
493{
494 Syscall::SC_clock_getres_params params { clock_id, result };
495 int rc = syscall(SC_clock_getres, ¶ms);
496 __RETURN_WITH_ERRNO(rc, rc, -1);
497}
498
499double difftime(time_t t1, time_t t0)
500{
501 return (double)(t1 - t0);
502}
503}