blob: 4b1819edb82f39ad7ca8614b084fc9d5007ee668 [file] [log] [blame]
// Copyright 2015 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "starboard/common/log.h"
#include "starboard/time_zone.h"
#define TZDEFAULT "/etc/localtime"
#define TZZONEINFOTAIL "/zoneinfo/"
#define isNonDigit(ch) (ch < '0' || '9' < ch)
static char gTimeZoneBuffer[PATH_MAX];
static char* gTimeZoneBufferPtr = NULL;
static bool isValidOlsonID(const char* id) {
int32_t idx = 0;
/* Determine if this is something like Iceland (Olson ID)
or AST4ADT (non-Olson ID) */
while (id[idx] && isNonDigit(id[idx]) && id[idx] != ',') {
idx++;
}
/* If we went through the whole string, then it might be okay.
The timezone is sometimes set to "CST-7CDT", "CST6CDT5,J129,J131/19:30",
"GRNLNDST3GRNLNDDT" or similar, so we cannot use it.
The rest of the time it could be an Olson ID. George */
return static_cast<bool>(id[idx] == 0 || strcmp(id, "PST8PDT") == 0 ||
strcmp(id, "MST7MDT") == 0 ||
strcmp(id, "CST6CDT") == 0 ||
strcmp(id, "EST5EDT") == 0);
}
// Similar to how ICU::putil.cpp gets IANA(Olsen) timezone ID.
const char* SbTimeZoneGetName() {
/*
This is a trick to look at the name of the link to get the Olson ID
because the tzfile contents is underspecified.
This isn't guaranteed to work because it may not be a symlink.
But this is production-tested solution for most versions of Linux.
*/
if (gTimeZoneBufferPtr == NULL) {
int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer,
sizeof(gTimeZoneBuffer) - 1);
if (0 < ret) {
int32_t tzZoneInfoTailLen = strlen(TZZONEINFOTAIL);
gTimeZoneBuffer[ret] = 0;
char* tzZoneInfoTailPtr = strstr(gTimeZoneBuffer, TZZONEINFOTAIL);
if (tzZoneInfoTailPtr != NULL &&
isValidOlsonID(tzZoneInfoTailPtr + tzZoneInfoTailLen)) {
return (gTimeZoneBufferPtr = tzZoneInfoTailPtr + tzZoneInfoTailLen);
}
}
SB_NOTREACHED();
return "";
} else {
return gTimeZoneBufferPtr;
}
}