Beispiel #1
0
/*
 * Get a pg_tz struct for the given timezone name.	Returns NULL if name
 * is invalid or not an "acceptable" zone.
 */
static pg_tz*
get_pg_tz_for_zone(const char *tzname)
{
	pg_tz* tz;

	if (!tzname || !tzname[0])
		return NULL;

	tz = pg_tzset(tzname);
	if (!tz)
		return NULL;

	if (!tz_acceptable(tz))
		return NULL;

	return tz;
}
Beispiel #2
0
/*
 * Set the global timezone. Verify that it's acceptable first.
 */
static bool
set_global_timezone(const char *tzname)
{
	pg_tz	   *tznew;

	if (!tzname || !tzname[0])
		return false;

	tznew = pg_tzset(tzname);
	if (!tznew)
		return false;

	if (!tz_acceptable(tznew))
		return false;

	global_timezone = tznew;
	return true;
}
Beispiel #3
0
/*
 * See how well a specific timezone setting matches the system behavior
 *
 * We score a timezone setting according to the number of test times it
 * matches.  (The test times are ordered later-to-earlier, but this routine
 * doesn't actually know that; it just scans until the first non-match.)
 *
 * We return -1 for a completely unusable setting; this is worse than the
 * score of zero for a setting that works but matches not even the first
 * test time.
 */
static int
score_timezone(const char *tzname, struct tztry * tt)
{
	int i;
	pg_time_t pgtt;
	struct tm* systm;
	struct pg_tm* pgtm;
	char cbuf[TZ_STRLEN_MAX + 1];
	pg_tz tz;


	/*
	 * Load timezone directly. Don't use pg_tzset, because we don't want all
	 * timezones loaded in the cache at startup.
	 */
	if (tzload(tzname, NULL, &tz.state, TRUE) != 0) {
		if (tzname[0] == ':' || tzparse(tzname, &tz.state, FALSE) != 0) {
			return -1;			/* can't handle the TZ name at all */
		}
	}

	/* Reject if leap seconds involved */
	if (!tz_acceptable(&tz)) {
		elog(DEBUG4, "Reject TZ \"%s\": uses leap seconds", tzname);
		return -1;
	}

	/* Check for match at all the test times */
	for (i = 0; i < tt->n_test_times; i++) {
		pgtt = (pg_time_t) (tt->test_times[i]);
		pgtm = pg_localtime(&pgtt, &tz);
		if (!pgtm)
			return -1;			/* probably shouldn't happen */

		systm = localtime(&(tt->test_times[i]));
		if (!systm) {
			elog(DEBUG4,
				"TZ \"%s\" scores %d:"
				" at %ld %04d-%02d-%02d %02d:%02d:%02d %s, system had no data",
				tzname, i, (long) pgtt,
				pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday,
				pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec,
				pgtm->tm_isdst ? "dst" : "std");
			return i;
		}

		if (!compare_tm(systm, pgtm)) {
			elog(DEBUG4,
				"TZ \"%s\" scores %d:"
				" at %ld %04d-%02d-%02d %02d:%02d:%02d %s"
				" versus %04d-%02d-%02d %02d:%02d:%02d %s",
				tzname, i, (long) pgtt,
				pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday,
				pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec,
				pgtm->tm_isdst ? "dst" : "std",
				systm->tm_year + 1900, systm->tm_mon + 1, systm->tm_mday,
				systm->tm_hour, systm->tm_min, systm->tm_sec,
				systm->tm_isdst ? "dst" : "std");
			return i;
		}

		if (systm->tm_isdst >= 0) {
			/* Check match of zone names, too */
			if (pgtm->tm_zone == NULL)
				return -1;		/* probably shouldn't happen */

			memset(cbuf, 0, sizeof(cbuf));
			strftime(cbuf, sizeof(cbuf) - 1, "%Z", systm);		/* zone abbr */
			if (strcmp(cbuf, pgtm->tm_zone) != 0) {
				elog(DEBUG4, "TZ \"%s\" scores %d: at %ld \"%s\" versus \"%s\"",
					tzname, i, (long) pgtt,
					pgtm->tm_zone, cbuf);
				return i;
			}
		}
	}

	elog(DEBUG4, "TZ \"%s\" gets max score %d", tzname, i);
	return i;
}
Beispiel #4
0
pg_tz*
pg_tzenumerate_next(pg_tzenum *dir)
{
	while (dir->depth >= 0) {
		struct dirent *direntry;
		char fullname[MAX_PG_PATH];
		struct stat statbuf;

		direntry = read_dir(dir->dirdesc[dir->depth], dir->dirname[dir->depth]);
		if (!direntry) {
			/* End of this directory */
			free_dir(dir->dirdesc[dir->depth]);
			pfree(dir->dirname[dir->depth]);
			dir->depth--;
			continue;
		}

		if (direntry->d_name[0] == '.')
			continue;

		snprintf(fullname, MAX_PG_PATH, "%s/%s", dir->dirname[dir->depth], direntry->d_name);
		if (stat(fullname, &statbuf) != 0)
			ereport(ERROR, (
			errcode_file_access(),
			errmsg("could not stat \"%s\": %m", fullname)));

		if (S_ISDIR(statbuf.st_mode)) {
			/* Step into the subdirectory */
			if (dir->depth >= MAX_TZDIR_DEPTH - 1)
				ereport(ERROR, (
				errmsg_internal("timezone directory stack overflow")));

			dir->depth++;
			dir->dirname[dir->depth] = pstrdup(fullname);
			dir->dirdesc[dir->depth] = alloc_dir(fullname);
			if (!dir->dirdesc[dir->depth])
				ereport(ERROR, (
				errcode_file_access(),
				errmsg("could not open directory \"%s\": %m",
					fullname)));

			/* Start over reading in the new directory */
			continue;
		}

		/*
		 * Load this timezone using tzload() not pg_tzset(), so we don't fill
		 * the cache
		 */
		if (tzload(fullname + dir->baselen, dir->tz.TZname, &dir->tz.state, TRUE) != 0) {
			/* Zone could not be loaded, ignore it */
			continue;
		}

		if (!tz_acceptable(&dir->tz)) {
			/* Ignore leap-second zones */
			continue;
		}

		/* Timezone loaded OK. */
		return &dir->tz;
	}

	/* Nothing more found */
	return NULL;
}