gtimezone: Fallback to /var/db/zoneinfo on FreeBSD

The timezone setup utility of FreeBSD, tzsetup, which is run during the
installation, creates /etc/localtime by copying the chosen timezone file
from /usr/share/zoneinfo. Although it can correctly deal with the case
where /etc/localtime is a symlink, it is not the default and there is no
user interface to change the default copying behaviour.

Fortunately, tzsetup has been modified to write the name of the chosen
timezone to /var/db/zoneinfo in 2009, so we can know the name of the
current timezone by reading it. DragonflyBSD also seems to do the same
thing in its tzsetup.

https://svnweb.freebsd.org/changeset/base/198267
https://bugzilla.gnome.org/show_bug.cgi?id=795165
This commit is contained in:
Ting-Wei Lan 2018-04-29 01:47:15 +08:00 committed by Philip Withnall
parent 3d2ab4680d
commit 50677e9336

View File

@ -434,23 +434,41 @@ zone_info_unix (const gchar *identifier,
{
gsize prefix_len = 0;
gchar *canonical_path = NULL;
GError *read_link_err = NULL;
filename = g_strdup ("/etc/localtime");
/* Resolve the actual timezone pointed to by /etc/localtime. */
resolved_identifier = g_file_read_link (filename, NULL);
resolved_identifier = g_file_read_link (filename, &read_link_err);
if (resolved_identifier == NULL)
{
/* Error */
if (out_identifier != NULL)
*out_identifier = NULL;
return NULL;
}
gboolean not_a_symlink = g_error_matches (read_link_err,
G_FILE_ERROR,
G_FILE_ERROR_INVAL);
g_clear_error (&read_link_err);
/* Resolve relative path */
canonical_path = g_canonicalize_filename (resolved_identifier, "/etc");
g_free (resolved_identifier);
resolved_identifier = g_steal_pointer (&canonical_path);
/* Fallback to the content of /var/db/zoneinfo if /etc/localtime is
* not a symlink. This is where 'tzsetup' program on FreeBSD and
* DragonflyBSD stores the timezone chosen by the user. */
if (not_a_symlink && g_file_get_contents ("/var/db/zoneinfo",
&resolved_identifier,
NULL, NULL))
g_strchomp (resolved_identifier);
else
{
/* Error */
if (out_identifier != NULL)
*out_identifier = NULL;
return NULL;
}
}
else
{
/* Resolve relative path */
canonical_path = g_canonicalize_filename (resolved_identifier, "/etc");
g_free (resolved_identifier);
resolved_identifier = g_steal_pointer (&canonical_path);
}
/* Strip the prefix and slashes if possible. */
if (g_str_has_prefix (resolved_identifier, tzdir))