View | Details | Raw Unified | Return to bug 796055
Collapse All | Expand All

(-)a/configure.ac (+58 lines)
Lines 43-48 dnl --------------------------------------------------------------------------- Link Here
43
dnl - Dependencies
43
dnl - Dependencies
44
dnl ---------------------------------------------------------------------------
44
dnl ---------------------------------------------------------------------------
45
45
46
DBUS_GLIB_REQUIRED_VERSION=0.74
46
GLIB_REQUIRED_VERSION=2.31.0
47
GLIB_REQUIRED_VERSION=2.31.0
47
GTK_REQUIRED_VERSION=3.3.18
48
GTK_REQUIRED_VERSION=3.3.18
48
GCONF_REQUIRED_VERSION=2.6.1
49
GCONF_REQUIRED_VERSION=2.6.1
Lines 116-121 AC_SUBST(LIBNOTIFY_CFLAGS) Link Here
116
AC_SUBST(LIBNOTIFY_LIBS)
117
AC_SUBST(LIBNOTIFY_LIBS)
117
118
118
dnl ---------------------------------------------------------------------------
119
dnl ---------------------------------------------------------------------------
120
dnl - Check for D-Bus
121
dnl ---------------------------------------------------------------------------
122
123
dnl - Are we specifying a different dbus root ?
124
AC_ARG_WITH(dbus-sys,
125
        [AC_HELP_STRING([--with-dbus-sys=<dir>],
126
        [where D-BUS system.d directory is])])
127
AC_ARG_WITH(dbus-services,
128
        [AC_HELP_STRING([--with-dbus-services=<dir>],
129
        [where D-BUS services directory is])])
130
if ! test -z "$with_dbus_sys" ; then
131
        DBUS_SYS_DIR="$with_dbus_sys"
132
else
133
        DBUS_SYS_DIR='${sysconfdir}/dbus-1/system.d'
134
fi
135
AC_SUBST(DBUS_SYS_DIR)
136
137
dnl ---------------------------------------------------------------------------
119
dnl - GUdev integration (default enabled)
138
dnl - GUdev integration (default enabled)
120
dnl ---------------------------------------------------------------------------
139
dnl ---------------------------------------------------------------------------
121
GUDEV_PKG=""
140
GUDEV_PKG=""
Lines 326-331 AM_CONDITIONAL(WITH_SYSTEMD, [test "$with_systemd" = "yes"], [Using systemd]) Link Here
326
345
327
346
328
# ---------------------------------------------------------------------------
347
# ---------------------------------------------------------------------------
348
# PolicyKit for the date & time mechanism
349
# ---------------------------------------------------------------------------
350
351
POLKIT_REQUIRED=0.97
352
DBUS_REQUIRED=1.1.2
353
354
# PolicyKit detection; defaults to 'auto' (use it if it's available)
355
#
356
POLKIT_CFLAGS=
357
POLKIT_LIBS=
358
AC_ARG_ENABLE(polkit,
359
              AS_HELP_STRING([--enable-polkit],
360
                             [Enable PolicyKit support (auto)]),
361
              enable_polkit=$enableval,
362
              enable_polkit=auto)
363
364
if test "x$enable_polkit" = "xno" ; then
365
  HAVE_POLKIT=no
366
else
367
  HAVE_POLKIT=no
368
  PKG_CHECK_MODULES(POLKIT, polkit-gobject-1 >= $POLKIT_REQUIRED dbus-1 >= $DBUS_REQUIRED dbus-glib-1 >= $DBUS_GLIB_REQUIRED_VERSION, HAVE_POLKIT=yes, HAVE_POLKIT=no)
369
370
  if test "x$enable_polkit" = "xyes" -a "x$HAVE_POLKIT" = "xno" ; then
371
    AC_MSG_ERROR(PolicyKit support explicity enabled but not available)
372
  fi
373
374
  if test "x$HAVE_POLKIT" = "xyes" ; then
375
    AC_DEFINE(HAVE_POLKIT, 1, [Defined if PolicyKit support is enabled])
376
  fi
377
fi
378
AM_CONDITIONAL(HAVE_POLKIT, test "x$HAVE_POLKIT" = "xyes")
379
AC_SUBST(POLKIT_CFLAGS)
380
AC_SUBST(POLKIT_LIBS)
381
382
383
# ---------------------------------------------------------------------------
329
# CUPS
384
# CUPS
330
# ---------------------------------------------------------------------------
385
# ---------------------------------------------------------------------------
331
386
Lines 457-462 plugins/clipboard/Makefile Link Here
457
plugins/color/Makefile
512
plugins/color/Makefile
458
plugins/common/Makefile
513
plugins/common/Makefile
459
plugins/cursor/Makefile
514
plugins/cursor/Makefile
515
plugins/datetime/Makefile
460
plugins/dummy/Makefile
516
plugins/dummy/Makefile
461
plugins/power/Makefile
517
plugins/power/Makefile
462
plugins/housekeeping/Makefile
518
plugins/housekeeping/Makefile
Lines 515-520 echo " Link Here
515
        Maintainer mode:          ${USE_MAINTAINER_MODE}
571
        Maintainer mode:          ${USE_MAINTAINER_MODE}
516
572
517
        Session tracking:         ${SESSION_TRACKING}
573
        Session tracking:         ${SESSION_TRACKING}
574
        dbus-1 system.d dir:      ${DBUS_SYS_DIR}
575
        PolicyKit support:        ${HAVE_POLKIT}
518
        LCMS DICT support:        ${have_new_lcms}
576
        LCMS DICT support:        ${have_new_lcms}
519
577
520
        Libnotify support:        ${have_libnotify}
578
        Libnotify support:        ${have_libnotify}
(-)a/plugins/Makefile.am (+1 lines)
Lines 8-13 enabled_plugins = \ Link Here
8
	clipboard	\
8
	clipboard	\
9
	color		\
9
	color		\
10
	cursor		\
10
	cursor		\
11
	datetime	\
11
	dummy		\
12
	dummy		\
12
	power		\
13
	power		\
13
	housekeeping    \
14
	housekeeping    \
(-)a/plugins/datetime/Makefile.am (+68 lines)
Line 0 Link Here
1
plugin_name = datetime
2
3
dbus_servicesdir = $(datadir)/dbus-1/system-services
4
dbus_confdir = $(sysconfdir)/dbus-1/system.d
5
polkitdir = $(datadir)/polkit-1/actions
6
7
dbus_services_in_files = org.gnome.SettingsDaemon.DateTimeMechanism.service.in
8
polkit_in_files = org.gnome.settingsdaemon.datetimemechanism.policy.in
9
10
gsd-datetime-mechanism-glue.h: $(srcdir)/gsd-datetime-mechanism.xml
11
	$(AM_V_GEN) dbus-binding-tool \
12
			--prefix=gsd_datetime_mechanism --mode=glib-server	\
13
			--output=gsd-datetime-mechanism-glue.h			\
14
			$(srcdir)/gsd-datetime-mechanism.xml
15
16
17
if HAVE_POLKIT
18
libexec_PROGRAMS = gsd-datetime-mechanism
19
noinst_PROGRAMS = test-system-timezone
20
endif
21
22
gsd_datetime_mechanism_SOURCES =		\
23
	gsd-datetime-mechanism.c		\
24
	gsd-datetime-mechanism.h		\
25
	gsd-datetime-mechanism-suse.c		\
26
	gsd-datetime-mechanism-suse.h		\
27
	gsd-datetime-mechanism-main.c		\
28
	system-timezone.c			\
29
	system-timezone.h
30
31
32
if HAVE_POLKIT
33
BUILT_SOURCES = gsd-datetime-mechanism-glue.h
34
endif
35
36
AM_CFLAGS = $(POLKIT_CFLAGS)
37
gsd_datetime_mechanism_LDADD = $(POLKIT_LIBS)
38
39
test_system_timezone_SOURCES = test-system-timezone.c system-timezone.c system-timezone.h
40
test_system_timezone_LDADD = $(POLKIT_LIBS)
41
42
if HAVE_POLKIT
43
dbus_services_DATA = $(dbus_services_in_files:.service.in=.service)
44
45
$(dbus_services_DATA): $(dbus_services_in_files)
46
	$(AM_V_GEN)sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@
47
48
dbus_conf_DATA = org.gnome.SettingsDaemon.DateTimeMechanism.conf
49
50
@INTLTOOL_POLICY_RULE@
51
polkit_DATA = $(polkit_in_files:.policy.in=.policy)
52
53
else
54
dbus_services_DATA =
55
dbus_conf_DATA =
56
polkit_DATA =
57
endif
58
59
EXTRA_DIST =						\
60
	$(dbus_services_in_files)			\
61
	org.gnome.SettingsDaemon.DateTimeMechanism.conf	\
62
	$(polkit_in_files)				\
63
	gsd-datetime-mechanism.xml
64
65
CLEANFILES = 		\
66
	org.gnome.SettingsDaemon.DateTimeMechanism.service	\
67
	org.gnome.settingsdaemon.datetimemechanism.policy	\
68
	$(BUILT_SOURCES)
(-)a/plugins/datetime/gsd-datetime-mechanism-main.c (+171 lines)
Line 0 Link Here
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 *
3
 * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 *
19
 */
20
21
#ifdef HAVE_CONFIG_H
22
#  include "config.h"
23
#endif
24
25
#include <stdlib.h>
26
#include <stdio.h>
27
#include <unistd.h>
28
#include <signal.h>
29
#include <errno.h>
30
#include <string.h>
31
#include <sys/types.h>
32
#include <sys/stat.h>
33
#include <fcntl.h>
34
35
#include <glib.h>
36
#include <glib-object.h>
37
38
#include <dbus/dbus-glib.h>
39
#include <dbus/dbus-glib-lowlevel.h>
40
41
42
#include "gsd-datetime-mechanism.h"
43
44
static DBusGProxy *
45
get_bus_proxy (DBusGConnection *connection)
46
{
47
        DBusGProxy *bus_proxy;
48
49
	bus_proxy = dbus_g_proxy_new_for_name (connection,
50
                                               DBUS_SERVICE_DBUS,
51
                                               DBUS_PATH_DBUS,
52
                                               DBUS_INTERFACE_DBUS);
53
        return bus_proxy;
54
}
55
56
#define BUS_NAME "org.gnome.SettingsDaemon.DateTimeMechanism"
57
58
static gboolean
59
acquire_name_on_proxy (DBusGProxy *bus_proxy)
60
{
61
        GError     *error;
62
        guint       result;
63
        gboolean    res;
64
        gboolean    ret;
65
66
        ret = FALSE;
67
68
        if (bus_proxy == NULL) {
69
                goto out;
70
        }
71
72
        error = NULL;
73
	res = dbus_g_proxy_call (bus_proxy,
74
                                 "RequestName",
75
                                 &error,
76
                                 G_TYPE_STRING, BUS_NAME,
77
                                 G_TYPE_UINT, 0,
78
                                 G_TYPE_INVALID,
79
                                 G_TYPE_UINT, &result,
80
                                 G_TYPE_INVALID);
81
        if (! res) {
82
                if (error != NULL) {
83
                        g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message);
84
                        g_error_free (error);
85
                } else {
86
                        g_warning ("Failed to acquire %s", BUS_NAME);
87
                }
88
                goto out;
89
	}
90
91
 	if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
92
                if (error != NULL) {
93
                        g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message);
94
                        g_error_free (error);
95
                } else {
96
                        g_warning ("Failed to acquire %s", BUS_NAME);
97
                }
98
                goto out;
99
        }
100
101
        ret = TRUE;
102
103
 out:
104
        return ret;
105
}
106
107
static DBusGConnection *
108
get_system_bus (void)
109
{
110
        GError          *error;
111
        DBusGConnection *bus;
112
113
        error = NULL;
114
        bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
115
        if (bus == NULL) {
116
                g_warning ("Couldn't connect to system bus: %s", error->message);
117
                g_error_free (error);
118
        }
119
        return bus;
120
}
121
122
int
123
main (int argc, char **argv)
124
{
125
        GMainLoop             *loop;
126
        GsdDatetimeMechanism  *mechanism;
127
        DBusGProxy            *bus_proxy;
128
        DBusGConnection       *connection;
129
        int                    ret;
130
131
        ret = 1;
132
133
        if (! g_thread_supported ()) {
134
                g_thread_init (NULL);
135
        }
136
        dbus_g_thread_init ();
137
        g_type_init ();
138
139
        connection = get_system_bus ();
140
        if (connection == NULL) {
141
                goto out;
142
        }
143
144
        bus_proxy = get_bus_proxy (connection);
145
        if (bus_proxy == NULL) {
146
                g_warning ("Could not construct bus_proxy object; bailing out");
147
                goto out;
148
        }
149
150
        if (!acquire_name_on_proxy (bus_proxy) ) {
151
                g_warning ("Could not acquire name; bailing out");
152
                goto out;
153
        }
154
155
        mechanism = gsd_datetime_mechanism_new ();
156
157
        if (mechanism == NULL) {
158
                goto out;
159
        }
160
161
        loop = g_main_loop_new (NULL, FALSE);
162
163
        g_main_loop_run (loop);
164
165
        g_object_unref (mechanism);
166
        g_main_loop_unref (loop);
167
        ret = 0;
168
169
out:
170
        return ret;
171
}
(-)a/plugins/datetime/gsd-datetime-mechanism-suse.c (+187 lines)
Line 0 Link Here
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 *
3
 * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
4
 * Copyright (C) 2011 Bastien Nocera <hadess@hadess.net>
5
 * Copyright (C) 2011 Vincent Untz <vuntz@gnome.org>
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
 *
21
 */
22
23
#ifdef HAVE_CONFIG_H
24
#  include "config.h"
25
#endif
26
27
#include <string.h>
28
29
#include "gsd-datetime-mechanism-suse.h"
30
#include "gsd-datetime-mechanism.h"
31
32
gboolean
33
_get_using_ntp_suse (DBusGMethodInvocation   *context)
34
{
35
        int exit_status;
36
        GError *error = NULL;
37
        gboolean can_use_ntp;
38
        gboolean is_using_ntp;
39
40
        if (g_file_test ("/etc/ntp.conf", G_FILE_TEST_EXISTS)) {
41
                can_use_ntp = TRUE;
42
                if (!g_spawn_command_line_sync ("/sbin/service ntp status",
43
                                                NULL, NULL, &exit_status, &error)) {
44
                        GError *error2;
45
                        error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
46
                                              GSD_DATETIME_MECHANISM_ERROR_GENERAL,
47
                                              "Error spawning /sbin/service: %s", error->message);
48
                        g_error_free (error);
49
                        dbus_g_method_return_error (context, error2);
50
                        g_error_free (error2);
51
                        return FALSE;
52
                }
53
                if (exit_status == 0)
54
                        is_using_ntp = TRUE;
55
                else
56
                        is_using_ntp = FALSE;
57
        }
58
        else {
59
                can_use_ntp = FALSE;
60
                is_using_ntp = FALSE;
61
        }
62
63
        dbus_g_method_return (context, can_use_ntp, is_using_ntp);
64
        return TRUE;
65
}
66
67
gboolean
68
_set_using_ntp_suse (DBusGMethodInvocation   *context,
69
                     gboolean                 using_ntp)
70
{
71
        GError *error;
72
        int exit_status;
73
        char *cmd;
74
75
        error = NULL;
76
77
        /* We omit --level 2345 so that systemd doesn't try to use the
78
         * SysV init scripts */
79
        cmd = g_strconcat ("/sbin/chkconfig ntp ", using_ntp ? "on" : "off", NULL);
80
81
        if (!g_spawn_command_line_sync (cmd,
82
                                        NULL, NULL, &exit_status, &error)) {
83
                GError *error2;
84
                error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
85
                                      GSD_DATETIME_MECHANISM_ERROR_GENERAL,
86
                                      "Error spawning '%s': %s", cmd, error->message);
87
                g_error_free (error);
88
                dbus_g_method_return_error (context, error2);
89
                g_error_free (error2);
90
                g_free (cmd);
91
                return FALSE;
92
        }
93
94
        g_free (cmd);
95
96
        cmd = g_strconcat ("/sbin/service ntp ", using_ntp ? "restart" : "stop", NULL);;
97
98
        if (!g_spawn_command_line_sync (cmd,
99
                                        NULL, NULL, &exit_status, &error)) {
100
                GError *error2;
101
                error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
102
                                      GSD_DATETIME_MECHANISM_ERROR_GENERAL,
103
                                      "Error spawning '%s': %s", cmd, error->message);
104
                g_error_free (error);
105
                dbus_g_method_return_error (context, error2);
106
                g_error_free (error2);
107
                g_free (cmd);
108
                return FALSE;
109
        }
110
111
        g_free (cmd);
112
113
        dbus_g_method_return (context);
114
        return TRUE;
115
}
116
117
gboolean
118
_update_etc_sysconfig_clock_suse (DBusGMethodInvocation *context, const char *key, const char *value)
119
{
120
        char **lines;
121
        int n;
122
        gboolean replaced;
123
        char *data;
124
        gsize len;
125
        GError *error;
126
127
        /* On SUSE variants, the /etc/sysconfig/clock file needs to be kept in sync */
128
        if (!g_file_test ("/etc/sysconfig/clock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
129
                error = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
130
                                      GSD_DATETIME_MECHANISM_ERROR_GENERAL,
131
                                      "Error reading /etc/sysconfig/clock file: %s", "No such file");
132
                dbus_g_method_return_error (context, error);
133
                g_error_free (error);
134
                return FALSE;
135
	}
136
137
        error = NULL;
138
139
        if (!g_file_get_contents ("/etc/sysconfig/clock", &data, &len, &error)) {
140
                GError *error2;
141
                error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
142
                                      GSD_DATETIME_MECHANISM_ERROR_GENERAL,
143
                                      "Error reading /etc/sysconfig/clock file: %s", error->message);
144
                g_error_free (error);
145
                dbus_g_method_return_error (context, error2);
146
                g_error_free (error2);
147
                return FALSE;
148
        }
149
        replaced = FALSE;
150
        lines = g_strsplit (data, "\n", 0);
151
        g_free (data);
152
153
        for (n = 0; lines[n] != NULL; n++) {
154
                if (g_str_has_prefix (lines[n], key)) {
155
                        g_free (lines[n]);
156
                        lines[n] = g_strdup_printf ("%s%s", key, value);
157
                        replaced = TRUE;
158
                }
159
        }
160
        if (replaced) {
161
                GString *str;
162
163
                str = g_string_new (NULL);
164
                for (n = 0; lines[n] != NULL; n++) {
165
                        g_string_append (str, lines[n]);
166
                        if (lines[n + 1] != NULL)
167
                                g_string_append_c (str, '\n');
168
                }
169
                data = g_string_free (str, FALSE);
170
                len = strlen (data);
171
                if (!g_file_set_contents ("/etc/sysconfig/clock", data, len, &error)) {
172
                        GError *error2;
173
                        error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
174
                                              GSD_DATETIME_MECHANISM_ERROR_GENERAL,
175
                                              "Error updating /etc/sysconfig/clock: %s", error->message);
176
                        g_error_free (error);
177
                        dbus_g_method_return_error (context, error2);
178
                        g_error_free (error2);
179
                        g_free (data);
180
                        return FALSE;
181
                }
182
                g_free (data);
183
        }
184
        g_strfreev (lines);
185
186
        return TRUE;
187
}
(-)a/plugins/datetime/gsd-datetime-mechanism-suse.h (+32 lines)
Line 0 Link Here
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 *
3
 * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
4
 * Copyright (C) 2011 Bastien Nocera <hadess@hadess.net>
5
 * Copyright (C) 2011 Vincent Untz <vuntz@gnome.org>
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
 *
21
 */
22
23
#include <glib.h>
24
#include <dbus/dbus-glib.h>
25
26
gboolean _get_using_ntp_suse  (DBusGMethodInvocation   *context);
27
gboolean _set_using_ntp_suse  (DBusGMethodInvocation   *context,
28
                               gboolean                 using_ntp);
29
gboolean _update_etc_sysconfig_clock_suse
30
                                (DBusGMethodInvocation *context,
31
                                 const char            *key,
32
                                 const char            *value);
(-)a/plugins/datetime/gsd-datetime-mechanism.c (+725 lines)
Line 0 Link Here
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 *
3
 * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 *
19
 */
20
21
#ifdef HAVE_CONFIG_H
22
#  include "config.h"
23
#endif
24
25
#include <stdlib.h>
26
#include <stdio.h>
27
#include <fcntl.h>
28
#include <unistd.h>
29
#include <string.h>
30
#include <sys/wait.h>
31
#include <errno.h>
32
#include <sys/time.h>
33
34
#include <glib.h>
35
#include <glib-object.h>
36
37
#include <dbus/dbus-glib.h>
38
#include <dbus/dbus-glib-lowlevel.h>
39
40
#include <polkit/polkit.h>
41
42
#include "system-timezone.h"
43
44
#include "gsd-datetime-mechanism.h"
45
#include "gsd-datetime-mechanism-glue.h"
46
#include "gsd-datetime-mechanism-suse.h"
47
48
static gboolean
49
do_exit (gpointer user_data)
50
{
51
        g_debug ("Exiting due to inactivity");
52
        exit (1);
53
        return FALSE;
54
}
55
56
static void
57
reset_killtimer (void)
58
{
59
        static guint timer_id = 0;
60
61
        if (timer_id > 0) {
62
                g_source_remove (timer_id);
63
        }
64
        g_debug ("Setting killtimer to 30 seconds...");
65
        timer_id = g_timeout_add_seconds (30, do_exit, NULL);
66
}
67
68
struct GsdDatetimeMechanismPrivate
69
{
70
        DBusGConnection *system_bus_connection;
71
        DBusGProxy      *system_bus_proxy;
72
        PolkitAuthority *auth;
73
};
74
75
static void     gsd_datetime_mechanism_finalize    (GObject     *object);
76
77
G_DEFINE_TYPE (GsdDatetimeMechanism, gsd_datetime_mechanism, G_TYPE_OBJECT)
78
79
#define GSD_DATETIME_MECHANISM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_DATETIME_TYPE_MECHANISM, GsdDatetimeMechanismPrivate))
80
81
GQuark
82
gsd_datetime_mechanism_error_quark (void)
83
{
84
        static GQuark ret = 0;
85
86
        if (ret == 0) {
87
                ret = g_quark_from_static_string ("gsd_datetime_mechanism_error");
88
        }
89
90
        return ret;
91
}
92
93
94
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
95
96
GType
97
gsd_datetime_mechanism_error_get_type (void)
98
{
99
        static GType etype = 0;
100
        
101
        if (etype == 0)
102
        {
103
                static const GEnumValue values[] =
104
                        {
105
                                ENUM_ENTRY (GSD_DATETIME_MECHANISM_ERROR_GENERAL, "GeneralError"),
106
                                ENUM_ENTRY (GSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
107
                                ENUM_ENTRY (GSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE, "InvalidTimezoneFile"),
108
                                { 0, 0, 0 }
109
                        };
110
                
111
                g_assert (GSD_DATETIME_MECHANISM_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
112
                
113
                etype = g_enum_register_static ("GsdDatetimeMechanismError", values);
114
        }
115
        
116
        return etype;
117
}
118
119
120
static GObject *
121
gsd_datetime_mechanism_constructor (GType                  type,
122
                                    guint                  n_construct_properties,
123
                                    GObjectConstructParam *construct_properties)
124
{
125
        GsdDatetimeMechanism      *mechanism;
126
127
        mechanism = GSD_DATETIME_MECHANISM (G_OBJECT_CLASS (gsd_datetime_mechanism_parent_class)->constructor (
128
                                                type,
129
                                                n_construct_properties,
130
                                                construct_properties));
131
132
        return G_OBJECT (mechanism);
133
}
134
135
static void
136
gsd_datetime_mechanism_class_init (GsdDatetimeMechanismClass *klass)
137
{
138
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
139
140
        object_class->constructor = gsd_datetime_mechanism_constructor;
141
        object_class->finalize = gsd_datetime_mechanism_finalize;
142
143
        g_type_class_add_private (klass, sizeof (GsdDatetimeMechanismPrivate));
144
145
        dbus_g_object_type_install_info (GSD_DATETIME_TYPE_MECHANISM, &dbus_glib_gsd_datetime_mechanism_object_info);
146
147
        dbus_g_error_domain_register (GSD_DATETIME_MECHANISM_ERROR, NULL, GSD_DATETIME_MECHANISM_TYPE_ERROR);
148
149
}
150
151
static void
152
gsd_datetime_mechanism_init (GsdDatetimeMechanism *mechanism)
153
{
154
        mechanism->priv = GSD_DATETIME_MECHANISM_GET_PRIVATE (mechanism);
155
156
}
157
158
static void
159
gsd_datetime_mechanism_finalize (GObject *object)
160
{
161
        GsdDatetimeMechanism *mechanism;
162
163
        g_return_if_fail (object != NULL);
164
        g_return_if_fail (GSD_DATETIME_IS_MECHANISM (object));
165
166
        mechanism = GSD_DATETIME_MECHANISM (object);
167
168
        g_return_if_fail (mechanism->priv != NULL);
169
170
        g_object_unref (mechanism->priv->system_bus_proxy);
171
172
        G_OBJECT_CLASS (gsd_datetime_mechanism_parent_class)->finalize (object);
173
}
174
175
static gboolean
176
register_mechanism (GsdDatetimeMechanism *mechanism)
177
{
178
        GError *error = NULL;
179
180
        mechanism->priv->auth = polkit_authority_get_sync (NULL, &error);
181
        if (mechanism->priv->auth == NULL) {
182
                if (error != NULL) {
183
                        g_critical ("error getting system bus: %s", error->message);
184
                        g_error_free (error);
185
                }
186
                goto error;
187
        }
188
189
        mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
190
        if (mechanism->priv->system_bus_connection == NULL) {
191
                if (error != NULL) {
192
                        g_critical ("error getting system bus: %s", error->message);
193
                        g_error_free (error);
194
                }
195
                goto error;
196
        }
197
198
        dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/", 
199
                                             G_OBJECT (mechanism));
200
201
        mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection,
202
                                                                      DBUS_SERVICE_DBUS,
203
                                                                      DBUS_PATH_DBUS,
204
                                                                      DBUS_INTERFACE_DBUS);
205
206
        reset_killtimer ();
207
208
        return TRUE;
209
210
error:
211
        return FALSE;
212
}
213
214
215
GsdDatetimeMechanism *
216
gsd_datetime_mechanism_new (void)
217
{
218
        GObject *object;
219
        gboolean res;
220
221
        object = g_object_new (GSD_DATETIME_TYPE_MECHANISM, NULL);
222
223
        res = register_mechanism (GSD_DATETIME_MECHANISM (object));
224
        if (! res) {
225
                g_object_unref (object);
226
                return NULL;
227
        }
228
229
        return GSD_DATETIME_MECHANISM (object);
230
}
231
232
static gboolean
233
_check_polkit_for_action (GsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context)
234
{
235
        const char *action = "org.gnome.settingsdaemon.datetimemechanism.configure";
236
        const char *sender;
237
        GError *error;
238
        PolkitSubject *subject;
239
        PolkitAuthorizationResult *result;
240
241
        error = NULL;
242
243
        /* Check that caller is privileged */
244
        sender = dbus_g_method_get_sender (context);
245
        subject = polkit_system_bus_name_new (sender);
246
247
        result = polkit_authority_check_authorization_sync (mechanism->priv->auth,
248
                                                            subject,
249
                                                            action,
250
                                                            NULL,
251
                                                            POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
252
                                                            NULL, &error);
253
        g_object_unref (subject);
254
255
        if (error) {
256
                dbus_g_method_return_error (context, error);
257
                g_error_free (error);
258
259
                return FALSE;
260
        }
261
262
        if (!polkit_authorization_result_get_is_authorized (result)) {
263
                error = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
264
                                     GSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED,
265
                                     "Not Authorized for action %s", action);
266
                dbus_g_method_return_error (context, error);
267
                g_error_free (error);
268
                g_object_unref (result);
269
270
                return FALSE;
271
        }
272
273
        g_object_unref (result);
274
275
        return TRUE;
276
}
277
278
static gboolean
279
_sync_hwclock (DBusGMethodInvocation *context)
280
{
281
        GError *error;
282
283
        error = NULL;
284
285
        if (g_file_test ("/sbin/hwclock",
286
                         G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE)) {
287
                int exit_status;
288
                if (!g_spawn_command_line_sync ("/sbin/hwclock --systohc", NULL, NULL, &exit_status, &error)) {
289
                        GError *error2;
290
                        error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
291
                                              GSD_DATETIME_MECHANISM_ERROR_GENERAL,
292
                                              "Error spawning /sbin/hwclock: %s", error->message);
293
                        g_error_free (error);
294
                        dbus_g_method_return_error (context, error2);
295
                        g_error_free (error2);
296
                        return FALSE;
297
                }
298
                if (WEXITSTATUS (exit_status) != 0) {
299
                        error = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
300
                                             GSD_DATETIME_MECHANISM_ERROR_GENERAL,
301
                                             "/sbin/hwclock returned %d", exit_status);
302
                        dbus_g_method_return_error (context, error);
303
                        g_error_free (error);
304
                        return FALSE;
305
                }
306
        }
307
308
        return TRUE;
309
}
310
311
static gboolean
312
_set_time (GsdDatetimeMechanism  *mechanism,
313
           const struct timeval  *tv,
314
           DBusGMethodInvocation *context)
315
{
316
        GError *error;
317
318
        if (!_check_polkit_for_action (mechanism, context))
319
                return FALSE;
320
321
        if (settimeofday (tv, NULL) != 0) {
322
                error = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
323
                                     GSD_DATETIME_MECHANISM_ERROR_GENERAL,
324
                                     "Error calling settimeofday({%lld,%lld}): %s",
325
                                     (gint64) tv->tv_sec, (gint64) tv->tv_usec,
326
                                     strerror (errno));
327
                dbus_g_method_return_error (context, error);
328
                g_error_free (error);
329
                return FALSE;
330
        }
331
332
        if (!_sync_hwclock (context))
333
                return FALSE;
334
335
        dbus_g_method_return (context);
336
        return TRUE;
337
}
338
339
static gboolean
340
_set_date (GsdDatetimeMechanism  *mechanism,
341
           guint                  day,
342
           guint                  month,
343
           guint                  year,
344
           DBusGMethodInvocation *context)
345
{
346
        GDateTime *time;
347
        char *date_str, *time_str;
348
        char *date_cmd;
349
        int exit_status;
350
        GError *error;
351
352
        date_str = g_strdup_printf ("%02d/%02d/%d", month, day, year);
353
        error = NULL;
354
355
        time = g_date_time_new_now_local ();
356
        time_str = g_date_time_format (time, "%R:%S");
357
        g_date_time_unref (time);
358
359
        date_cmd = g_strdup_printf ("/bin/date -s \"%s %s\" +\"%%D %%R:%%S\"", date_str, time_str);
360
        g_free (date_str);
361
        g_free (time_str);
362
363
        if (!g_spawn_command_line_sync (date_cmd, NULL, NULL, &exit_status, &error)) {
364
                GError *error2;
365
                error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
366
                                      GSD_DATETIME_MECHANISM_ERROR_GENERAL,
367
                                      "Error spawning /bin/date: %s", error->message);
368
                g_error_free (error);
369
                dbus_g_method_return_error (context, error2);
370
                g_error_free (error2);
371
                g_free (date_cmd);
372
                return FALSE;
373
        }
374
        g_free (date_cmd);
375
        if (WEXITSTATUS (exit_status) != 0) {
376
                error = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
377
                                     GSD_DATETIME_MECHANISM_ERROR_GENERAL,
378
                                     "/bin/date returned %d", exit_status);
379
                dbus_g_method_return_error (context, error);
380
                g_error_free (error);
381
                return FALSE;
382
        }
383
384
        if (!_sync_hwclock (context))
385
                return FALSE;
386
387
        return TRUE;
388
}
389
390
/* exported methods */
391
392
gboolean
393
gsd_datetime_mechanism_set_time (GsdDatetimeMechanism  *mechanism,
394
                                 gint64                 seconds_since_epoch,
395
                                 DBusGMethodInvocation *context)
396
{
397
        struct timeval tv;
398
399
        reset_killtimer ();
400
        g_debug ("SetTime(%" G_GINT64_FORMAT ") called", seconds_since_epoch);
401
402
        tv.tv_sec = (time_t) seconds_since_epoch;
403
        tv.tv_usec = 0;
404
        return _set_time (mechanism, &tv, context);
405
}
406
407
gboolean
408
gsd_datetime_mechanism_set_date (GsdDatetimeMechanism  *mechanism,
409
                                 guint                  day,
410
                                 guint                  month,
411
                                 guint                  year,
412
                                 DBusGMethodInvocation *context)
413
{
414
        reset_killtimer ();
415
        g_debug ("SetDate(%d, %d, %d) called", day, month, year);
416
417
        return _set_date (mechanism, day, month, year, context);
418
}
419
420
gboolean
421
gsd_datetime_mechanism_adjust_time (GsdDatetimeMechanism  *mechanism,
422
                                    gint64                 seconds_to_add,
423
                                    DBusGMethodInvocation *context)
424
{
425
        struct timeval tv;
426
427
        reset_killtimer ();
428
        g_debug ("AdjustTime(%" G_GINT64_FORMAT " ) called", seconds_to_add);
429
430
        if (gettimeofday (&tv, NULL) != 0) {
431
                GError *error;
432
                error = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
433
                                     GSD_DATETIME_MECHANISM_ERROR_GENERAL,
434
                                     "Error calling gettimeofday(): %s", strerror (errno));
435
                dbus_g_method_return_error (context, error);
436
                g_error_free (error);
437
                return FALSE;
438
        }
439
440
        tv.tv_sec += (time_t) seconds_to_add;
441
        return _set_time (mechanism, &tv, context);
442
}
443
444
static gboolean
445
gsd_datetime_check_tz_name (const char *tz,
446
                            GError    **error)
447
{
448
        GFile *file;
449
        char *tz_path, *actual_path;
450
        gboolean retval;
451
452
        retval = TRUE;
453
        tz_path = g_build_filename (SYSTEM_ZONEINFODIR, tz, NULL);
454
455
        /* Get the actual resolved path */
456
        file = g_file_new_for_path (tz_path);
457
        actual_path = g_file_get_path (file);
458
        g_object_unref (file);
459
460
        /* The tz name passed had relative paths in it */
461
        if (g_strcmp0 (tz_path, actual_path) != 0) {
462
                g_set_error (error, GSD_DATETIME_MECHANISM_ERROR,
463
                             GSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE,
464
                             "Timezone file '%s' was invalid.",
465
                             tz);
466
                retval = FALSE;
467
        }
468
469
        g_free (tz_path);
470
        g_free (actual_path);
471
472
        return retval;
473
}
474
475
gboolean
476
gsd_datetime_mechanism_set_timezone (GsdDatetimeMechanism  *mechanism,
477
                                     const char            *tz,
478
                                     DBusGMethodInvocation *context)
479
{
480
        GError *error;
481
482
        reset_killtimer ();
483
        g_debug ("SetTimezone('%s') called", tz);
484
485
        if (!_check_polkit_for_action (mechanism, context))
486
                return FALSE;
487
488
        error = NULL;
489
490
        if (!gsd_datetime_check_tz_name (tz, &error))
491
                return FALSE;
492
493
        if (!system_timezone_set (tz, &error)) {
494
                GError *error2;
495
                int     code;
496
497
                if (error->code == SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE)
498
                        code = GSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE;
499
                else
500
                        code = GSD_DATETIME_MECHANISM_ERROR_GENERAL;
501
502
                error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
503
                                      code, "%s", error->message);
504
505
                g_error_free (error);
506
507
                dbus_g_method_return_error (context, error2);
508
                g_error_free (error2);
509
510
                return FALSE;
511
        }
512
513
        dbus_g_method_return (context);
514
        return TRUE;
515
}
516
517
518
gboolean
519
gsd_datetime_mechanism_get_timezone (GsdDatetimeMechanism   *mechism,
520
                                     DBusGMethodInvocation  *context)
521
{
522
  gchar *timezone;
523
524
  reset_killtimer ();
525
526
  timezone = system_timezone_find ();
527
528
  dbus_g_method_return (context, timezone);
529
530
  return TRUE;
531
}
532
533
gboolean
534
gsd_datetime_mechanism_get_hardware_clock_using_utc (GsdDatetimeMechanism  *mechanism,
535
                                                     DBusGMethodInvocation *context)
536
{
537
        char **lines;
538
        char *data;
539
        gsize len;
540
        GError *error;
541
        gboolean is_utc;
542
543
        error = NULL;
544
545
        if (!g_file_get_contents ("/etc/adjtime", &data, &len, &error)) {
546
                GError *error2;
547
                error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
548
                                      GSD_DATETIME_MECHANISM_ERROR_GENERAL,
549
                                      "Error reading /etc/adjtime file: %s", error->message);
550
                g_error_free (error);
551
                dbus_g_method_return_error (context, error2);
552
                g_error_free (error2);
553
                return FALSE;
554
        }
555
556
        lines = g_strsplit (data, "\n", 0);
557
        g_free (data);
558
559
        if (g_strv_length (lines) < 3) {
560
                error = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
561
                                     GSD_DATETIME_MECHANISM_ERROR_GENERAL,
562
                                     "Cannot parse /etc/adjtime");
563
                dbus_g_method_return_error (context, error);
564
                g_error_free (error);
565
                g_strfreev (lines);
566
                return FALSE;
567
        }
568
569
        if (strcmp (lines[2], "UTC") == 0) {
570
                is_utc = TRUE;
571
        } else if (strcmp (lines[2], "LOCAL") == 0) {
572
                is_utc = FALSE;
573
        } else {
574
                error = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
575
                                     GSD_DATETIME_MECHANISM_ERROR_GENERAL,
576
                                     "Expected UTC or LOCAL at line 3 of /etc/adjtime; found '%s'", lines[2]);
577
                dbus_g_method_return_error (context, error);
578
                g_error_free (error);
579
                g_strfreev (lines);
580
                return FALSE;
581
        }
582
        g_strfreev (lines);
583
        dbus_g_method_return (context, is_utc);
584
        return TRUE;
585
}
586
587
gboolean
588
gsd_datetime_mechanism_set_hardware_clock_using_utc (GsdDatetimeMechanism  *mechanism,
589
                                                     gboolean               using_utc,
590
                                                     DBusGMethodInvocation *context)
591
{
592
        GError *error;
593
594
        error = NULL;
595
596
        if (!_check_polkit_for_action (mechanism, context))
597
                return FALSE;
598
599
        if (g_file_test ("/sbin/hwclock", 
600
                         G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE)) {
601
                int exit_status;
602
                char *cmd;
603
                cmd = g_strdup_printf ("/sbin/hwclock %s --systohc", using_utc ? "--utc" : "--localtime");
604
                if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) {
605
                        GError *error2;
606
                        error2 = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
607
                                              GSD_DATETIME_MECHANISM_ERROR_GENERAL,
608
                                              "Error spawning /sbin/hwclock: %s", error->message);
609
                        g_error_free (error);
610
                        dbus_g_method_return_error (context, error2);
611
                        g_error_free (error2);
612
                        g_free (cmd);
613
                        return FALSE;
614
                }
615
                g_free (cmd);
616
                if (WEXITSTATUS (exit_status) != 0) {
617
                        error = g_error_new (GSD_DATETIME_MECHANISM_ERROR,
618
                                             GSD_DATETIME_MECHANISM_ERROR_GENERAL,
619
                                             "/sbin/hwclock returned %d", exit_status);
620
                        dbus_g_method_return_error (context, error);
621
                        g_error_free (error);
622
                        return FALSE;
623
                }
624
625
                if (!_update_etc_sysconfig_clock_suse (context, "HWCLOCK=", using_utc ? "-u" : "--localtime"))
626
                        return FALSE;
627
        }
628
        dbus_g_method_return (context);
629
        return TRUE;
630
}
631
632
gboolean
633
gsd_datetime_mechanism_get_using_ntp  (GsdDatetimeMechanism    *mechanism,
634
                                       DBusGMethodInvocation   *context)
635
{
636
        return _get_using_ntp_suse (context);
637
}
638
639
gboolean
640
gsd_datetime_mechanism_set_using_ntp  (GsdDatetimeMechanism    *mechanism,
641
                                       gboolean                 using_ntp,
642
                                       DBusGMethodInvocation   *context)
643
{
644
        if (!_check_polkit_for_action (mechanism, context))
645
                return FALSE;
646
647
        return _set_using_ntp_suse (context, using_ntp);
648
}
649
650
static void
651
check_can_do (GsdDatetimeMechanism  *mechanism,
652
              const char            *action,
653
              DBusGMethodInvocation *context)
654
{
655
        const char *sender;
656
        PolkitSubject *subject;
657
        PolkitAuthorizationResult *result;
658
        GError *error;
659
660
        /* Check that caller is privileged */
661
        sender = dbus_g_method_get_sender (context);
662
        subject = polkit_system_bus_name_new (sender);
663
664
        error = NULL;
665
        result = polkit_authority_check_authorization_sync (mechanism->priv->auth,
666
                                                            subject,
667
                                                            action,
668
                                                            NULL,
669
                                                            0,
670
                                                            NULL,
671
                                                            &error);
672
        g_object_unref (subject);
673
674
        if (error) {
675
                dbus_g_method_return_error (context, error);
676
                g_error_free (error);
677
                return;
678
        }
679
680
        if (polkit_authorization_result_get_is_authorized (result)) {
681
                dbus_g_method_return (context, 2);
682
        }
683
        else if (polkit_authorization_result_get_is_challenge (result)) {
684
                dbus_g_method_return (context, 1);
685
        }
686
        else {
687
                dbus_g_method_return (context, 0);
688
        }
689
690
        g_object_unref (result);
691
}
692
693
694
gboolean
695
gsd_datetime_mechanism_can_set_time (GsdDatetimeMechanism  *mechanism,
696
                                     DBusGMethodInvocation *context)
697
{
698
        check_can_do (mechanism,
699
                      "org.gnome.settingsdaemon.datetimemechanism.configure",
700
                      context);
701
702
        return TRUE;
703
}
704
705
gboolean
706
gsd_datetime_mechanism_can_set_timezone (GsdDatetimeMechanism  *mechanism,
707
                                         DBusGMethodInvocation *context)
708
{
709
        check_can_do (mechanism,
710
                      "org.gnome.settingsdaemon.datetimemechanism.configure",
711
                      context);
712
713
        return TRUE;
714
}
715
716
gboolean
717
gsd_datetime_mechanism_can_set_using_ntp (GsdDatetimeMechanism  *mechanism,
718
                                          DBusGMethodInvocation *context)
719
{
720
        check_can_do (mechanism,
721
                      "org.gnome.settingsdaemon.datetimemechanism.configure",
722
                      context);
723
724
        return TRUE;
725
}
(-)a/plugins/datetime/gsd-datetime-mechanism.h (+112 lines)
Line 0 Link Here
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 *
3
 * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 *
19
 */
20
21
#ifndef GSD_DATETIME_MECHANISM_H
22
#define GSD_DATETIME_MECHANISM_H
23
24
#include <glib-object.h>
25
#include <dbus/dbus-glib.h>
26
27
G_BEGIN_DECLS
28
29
#define GSD_DATETIME_TYPE_MECHANISM         (gsd_datetime_mechanism_get_type ())
30
#define GSD_DATETIME_MECHANISM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_DATETIME_TYPE_MECHANISM, GsdDatetimeMechanism))
31
#define GSD_DATETIME_MECHANISM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GSD_DATETIME_TYPE_MECHANISM, GsdDatetimeMechanismClass))
32
#define GSD_DATETIME_IS_MECHANISM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_DATETIME_TYPE_MECHANISM))
33
#define GSD_DATETIME_IS_MECHANISM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_DATETIME_TYPE_MECHANISM))
34
#define GSD_DATETIME_MECHANISM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_DATETIME_TYPE_MECHANISM, GsdDatetimeMechanismClass))
35
36
typedef struct GsdDatetimeMechanismPrivate GsdDatetimeMechanismPrivate;
37
38
typedef struct
39
{
40
        GObject        parent;
41
        GsdDatetimeMechanismPrivate *priv;
42
} GsdDatetimeMechanism;
43
44
typedef struct
45
{
46
        GObjectClass   parent_class;
47
} GsdDatetimeMechanismClass;
48
49
typedef enum
50
{
51
        GSD_DATETIME_MECHANISM_ERROR_GENERAL,
52
        GSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED,
53
        GSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE,
54
        GSD_DATETIME_MECHANISM_NUM_ERRORS
55
} GsdDatetimeMechanismError;
56
57
#define GSD_DATETIME_MECHANISM_ERROR gsd_datetime_mechanism_error_quark ()
58
59
GType gsd_datetime_mechanism_error_get_type (void);
60
#define GSD_DATETIME_MECHANISM_TYPE_ERROR (gsd_datetime_mechanism_error_get_type ())
61
62
63
GQuark                     gsd_datetime_mechanism_error_quark         (void);
64
GType                      gsd_datetime_mechanism_get_type            (void);
65
GsdDatetimeMechanism      *gsd_datetime_mechanism_new                 (void);
66
67
/* exported methods */
68
gboolean            gsd_datetime_mechanism_get_timezone (GsdDatetimeMechanism   *mechanism,
69
                                                         DBusGMethodInvocation  *context);
70
gboolean            gsd_datetime_mechanism_set_timezone (GsdDatetimeMechanism   *mechanism,
71
                                                         const char             *zone_file,
72
                                                         DBusGMethodInvocation  *context);
73
74
gboolean            gsd_datetime_mechanism_can_set_timezone (GsdDatetimeMechanism  *mechanism,
75
                                                             DBusGMethodInvocation *context);
76
77
gboolean            gsd_datetime_mechanism_set_time     (GsdDatetimeMechanism  *mechanism,
78
                                                         gint64                 seconds_since_epoch,
79
                                                         DBusGMethodInvocation *context);
80
81
gboolean             gsd_datetime_mechanism_set_date     (GsdDatetimeMechanism  *mechanism,
82
                                                          guint                  day,
83
                                                          guint                  month,
84
                                                          guint                  year,
85
                                                          DBusGMethodInvocation *context);
86
87
gboolean            gsd_datetime_mechanism_can_set_time (GsdDatetimeMechanism  *mechanism,
88
                                                         DBusGMethodInvocation *context);
89
90
gboolean            gsd_datetime_mechanism_adjust_time  (GsdDatetimeMechanism  *mechanism,
91
                                                         gint64                 seconds_to_add,
92
                                                         DBusGMethodInvocation *context);
93
94
gboolean            gsd_datetime_mechanism_get_hardware_clock_using_utc  (GsdDatetimeMechanism  *mechanism,
95
                                                                          DBusGMethodInvocation *context);
96
97
gboolean            gsd_datetime_mechanism_set_hardware_clock_using_utc  (GsdDatetimeMechanism  *mechanism,
98
                                                                          gboolean               using_utc,
99
                                                                          DBusGMethodInvocation *context);
100
101
gboolean            gsd_datetime_mechanism_get_using_ntp  (GsdDatetimeMechanism    *mechanism,
102
                                                           DBusGMethodInvocation   *context);
103
104
gboolean            gsd_datetime_mechanism_set_using_ntp  (GsdDatetimeMechanism    *mechanism,
105
                                                           gboolean                 using_ntp,
106
                                                           DBusGMethodInvocation   *context);
107
108
gboolean            gsd_datetime_mechanism_can_set_using_ntp (GsdDatetimeMechanism  *mechanism,
109
                                                              DBusGMethodInvocation *context);
110
G_END_DECLS
111
112
#endif /* GSD_DATETIME_MECHANISM_H */
(-)a/plugins/datetime/gsd-datetime-mechanism.xml (+129 lines)
Line 0 Link Here
1
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
2
<node name="/">
3
  <interface name="org.gnome.SettingsDaemon.DateTimeMechanism">
4
    <method name="SetTimezone">
5
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
6
      <arg name="tz" direction="in" type="s"/>
7
    </method>
8
9
    <method name="GetTimezone">
10
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
11
      <arg name="timezone" direction="out" type="s"/>
12
    </method>
13
14
    <method name="CanSetTimezone">
15
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
16
      <arg name="value" direction="out" type="i">
17
        <doc:doc>
18
          <doc:summary>Whether the caller can set the timezone</doc:summary>
19
          <doc:description>
20
            <doc:para>
21
              The return value is not a boolean, but an integer with the following meaning:
22
              <doc:list>
23
                <doc:item>
24
                  <doc:term>0</doc:term>
25
                  <doc:definition>the caller cannot set the timezone</doc:definition>
26
                </doc:item>
27
                <doc:item>
28
                  <doc:term>1</doc:term>
29
                  <doc:definition>the caller will be challenged before being able to set the timezone</doc:definition>
30
                </doc:item>
31
                <doc:item>
32
                  <doc:term>2</doc:term>
33
                  <doc:definition>the caller is authorized to set the timezone</doc:definition>
34
                </doc:item>
35
              </doc:list>
36
            </doc:para>
37
          </doc:description>
38
        </doc:doc>
39
      </arg>
40
    </method>
41
    <method name="SetDate">
42
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
43
      <arg name="day" direction="in" type="u"/>
44
      <arg name="month" direction="in" type="u"/>
45
      <arg name="year" direction="in" type="u"/>
46
    </method>
47
    <method name="SetTime">
48
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
49
      <arg name="seconds_since_epoch" direction="in" type="x"/>
50
    </method>
51
    <method name="CanSetTime">
52
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
53
      <arg name="value" direction="out" type="i">
54
        <doc:doc>
55
          <doc:summary>Whether the caller can set the time</doc:summary>
56
          <doc:description>
57
            <doc:para>
58
              The return value is not a boolean, but an integer with the following meaning:
59
              <doc:list>
60
                <doc:item>
61
                  <doc:term>0</doc:term>
62
                  <doc:definition>the caller cannot set the time</doc:definition>
63
                </doc:item>
64
                <doc:item>
65
                  <doc:term>1</doc:term>
66
                  <doc:definition>the caller will be challenged before being able to set the time</doc:definition>
67
                </doc:item>
68
                <doc:item>
69
                  <doc:term>2</doc:term>
70
                  <doc:definition>the caller is authorized to set the time</doc:definition>
71
                </doc:item>
72
              </doc:list>
73
            </doc:para>
74
          </doc:description>
75
        </doc:doc>
76
      </arg>
77
    </method>
78
    <method name="AdjustTime">
79
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
80
      <arg name="seconds_to_add" direction="in" type="x"/>
81
    </method>
82
83
    <method name="GetHardwareClockUsingUtc">
84
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
85
      <arg name="is_using_utc" direction="out" type="b"/>
86
    </method>
87
    <method name="SetHardwareClockUsingUtc">
88
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
89
      <arg name="is_using_utc" direction="in" type="b"/>
90
    </method>
91
92
    <method name="GetUsingNtp">
93
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
94
      <arg name="can_use_ntp" direction="out" type="b"/>
95
      <arg name="is_using_ntp" direction="out" type="b"/>
96
    </method>
97
    <method name="SetUsingNtp">
98
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
99
      <arg name="is_using_ntp" direction="in" type="b"/>
100
    </method>
101
    <method name="CanSetUsingNtp">
102
      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
103
      <arg name="value" direction="out" type="i">
104
        <doc:doc>
105
          <doc:summary>Whether the caller can set the "use NTP" setting</doc:summary>
106
          <doc:description>
107
            <doc:para>
108
              The return value is not a boolean, but an integer with the following meaning:
109
              <doc:list>
110
                <doc:item>
111
                  <doc:term>0</doc:term>
112
                  <doc:definition>the caller cannot change the "use NTP" setting</doc:definition>
113
                </doc:item>
114
                <doc:item>
115
                  <doc:term>1</doc:term>
116
                  <doc:definition>the caller will be challenged before being able to change "use NTP" setting</doc:definition>
117
                </doc:item>
118
                <doc:item>
119
                  <doc:term>2</doc:term>
120
                  <doc:definition>the caller is authorized to change the "use NTP" setting</doc:definition>
121
                </doc:item>
122
              </doc:list>
123
            </doc:para>
124
          </doc:description>
125
        </doc:doc>
126
      </arg>
127
    </method>
128
  </interface>
129
</node>
(-)a/plugins/datetime/org.gnome.SettingsDaemon.DateTimeMechanism.conf (+19 lines)
Line 0 Link Here
1
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
2
3
<!DOCTYPE busconfig PUBLIC
4
 "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
5
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
6
<busconfig>
7
8
  <!-- Only root can own the service -->
9
  <policy user="root">
10
    <allow own="org.gnome.SettingsDaemon.DateTimeMechanism"/>
11
    <allow send_destination="org.gnome.SettingsDaemon.DateTimeMechanism"/>
12
  </policy>
13
14
  <!-- Allow anyone to invoke methods on the interfaces -->
15
  <policy context="default">
16
    <allow send_destination="org.gnome.SettingsDaemon.DateTimeMechanism"/>
17
  </policy>
18
19
</busconfig>
(-)a/plugins/datetime/org.gnome.SettingsDaemon.DateTimeMechanism.service.in (+4 lines)
Line 0 Link Here
1
[D-BUS Service]
2
Name=org.gnome.SettingsDaemon.DateTimeMechanism
3
Exec=@LIBEXECDIR@/gsd-datetime-mechanism
4
User=root
(-)a/plugins/datetime/org.gnome.settingsdaemon.datetimemechanism.policy.in (+21 lines)
Line 0 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE policyconfig PUBLIC
3
 "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
4
 "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
5
6
<policyconfig>
7
  <vendor>The GNOME Project</vendor>
8
  <vendor_url>http://www.gnome.org/</vendor_url>
9
  <icon_name>gnome-panel-clock</icon_name>
10
11
  <action id="org.gnome.settingsdaemon.datetimemechanism.configure">
12
    <_description>Change system time and date settings</_description>
13
    <_message>To change time or date settings, you need to authenticate.</_message>
14
    <defaults>
15
      <allow_any>no</allow_any>
16
      <allow_inactive>no</allow_inactive>
17
      <allow_active>auth_admin_keep</allow_active>
18
    </defaults>
19
  </action>
20
21
</policyconfig>
(-)a/plugins/datetime/system-timezone.c (+924 lines)
Line 0 Link Here
1
/* System timezone handling
2
 *
3
 * Copyright (C) 2008 Novell, Inc.
4
 *
5
 * Authors: Vincent Untz <vuntz@gnome.org>
6
 * 
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
 * 
21
 * Some code is based on previous code in clock-location.c and on code from
22
 * tz.c (shipped with version <= 2.22.0). Those files were under the same
23
 * license, with those authors and copyrights:
24
 * 
25
 * clock-location.c:
26
 * ================
27
 * No header, but most of the work was done (AFAIK) by
28
 * Federico Mena Quintero <federico@novell.com>
29
 * Matthias Clasen <mclasen@redhat.com>
30
 *
31
 * tz.c:
32
 * ====
33
 * Copyright (C) 2000-2001 Ximian, Inc.
34
 * Copyright (C) 2004 Sun Microsystems, Inc.
35
 *
36
 * Authors: Hans Petter Jansson <hpj@ximian.com>
37
 *	    additional functions by Erwann Chenede <erwann.chenede@sun.com>
38
 *	    reworked by Vincent Untz <vuntz@gnome.org>
39
 * 
40
 * Largely based on Michael Fulbright's work on Anaconda.
41
 */
42
43
/* FIXME: it'd be nice to filter out the timezones that we might get when
44
 * parsing config files that are not in zone.tab. Note that it's also wrong
45
 * in some cases: eg, in tzdata2008b, Asia/Calcutta got renamed to
46
 * Asia/Kolkata and the old name is not in zone.tab. */
47
48
#include <string.h>
49
#include <unistd.h>
50
51
#include <glib.h>
52
#include <glib/gstdio.h>
53
#include <gio/gio.h>
54
55
#include "system-timezone.h"
56
57
/* Files that we look at */
58
#define ETC_TIMEZONE        "/etc/timezone"
59
#define ETC_TIMEZONE_MAJ    "/etc/TIMEZONE"
60
#define ETC_RC_CONF         "/etc/rc.conf"
61
#define ETC_SYSCONFIG_CLOCK "/etc/sysconfig/clock"
62
#define ETC_CONF_D_CLOCK    "/etc/conf.d/clock"
63
#define ETC_LOCALTIME       "/etc/localtime"
64
65
/* The first 4 characters in a timezone file, from tzfile.h */
66
#define TZ_MAGIC "TZif"
67
68
static GObject *systz_singleton = NULL;
69
70
G_DEFINE_TYPE (SystemTimezone, system_timezone, G_TYPE_OBJECT)
71
72
typedef struct {
73
        char *tz;
74
        char *env_tz;
75
} SystemTimezonePrivate;
76
77
static GObject *system_timezone_constructor (GType                  type,
78
                                             guint                  n_construct_properties,
79
                                             GObjectConstructParam *construct_properties);
80
static void system_timezone_finalize (GObject *obj);
81
82
#define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezonePrivate))
83
84
SystemTimezone *
85
system_timezone_new (void)
86
{
87
        return g_object_new (SYSTEM_TIMEZONE_TYPE, NULL);
88
}
89
90
const char *
91
system_timezone_get (SystemTimezone *systz)
92
{
93
        SystemTimezonePrivate *priv;
94
95
        g_return_val_if_fail (IS_SYSTEM_TIMEZONE (systz), NULL);
96
97
        priv = PRIVATE (systz);
98
        return priv->tz;
99
}
100
101
const char *
102
system_timezone_get_env (SystemTimezone *systz)
103
{
104
        SystemTimezonePrivate *priv;
105
106
        g_return_val_if_fail (IS_SYSTEM_TIMEZONE (systz), NULL);
107
108
        priv = PRIVATE (systz);
109
        return priv->env_tz;
110
}
111
112
static void
113
system_timezone_class_init (SystemTimezoneClass *class)
114
{
115
        GObjectClass *g_obj_class = G_OBJECT_CLASS (class);
116
117
        g_obj_class->constructor = system_timezone_constructor;
118
        g_obj_class->finalize = system_timezone_finalize;
119
120
        g_type_class_add_private (class, sizeof (SystemTimezonePrivate));
121
}
122
123
static void
124
system_timezone_init (SystemTimezone *systz)
125
{
126
        SystemTimezonePrivate *priv = PRIVATE (systz);
127
128
        priv->tz = NULL;
129
        priv->env_tz = NULL;
130
}
131
132
static GObject *
133
system_timezone_constructor (GType                  type,
134
                             guint                  n_construct_properties,
135
                             GObjectConstructParam *construct_properties)
136
{
137
        GObject *obj;
138
        SystemTimezonePrivate *priv;
139
140
        /* This is a singleton, we don't need to have it per-applet */
141
        if (systz_singleton)
142
                return g_object_ref (systz_singleton);
143
144
        obj = G_OBJECT_CLASS (system_timezone_parent_class)->constructor (
145
                                                type,
146
                                                n_construct_properties,
147
                                                construct_properties);
148
149
        priv = PRIVATE (obj);
150
151
        priv->tz = system_timezone_find ();
152
153
        priv->env_tz = g_strdup (g_getenv ("TZ"));
154
155
        systz_singleton = obj;
156
157
        return systz_singleton;
158
}
159
160
static void
161
system_timezone_finalize (GObject *obj)
162
{
163
        SystemTimezonePrivate *priv = PRIVATE (obj);
164
165
        if (priv->tz) {
166
                g_free (priv->tz);
167
                priv->tz = NULL;
168
        }
169
170
        if (priv->env_tz) {
171
                g_free (priv->env_tz);
172
                priv->env_tz = NULL;
173
        }
174
175
        G_OBJECT_CLASS (system_timezone_parent_class)->finalize (obj);
176
177
        g_assert (obj == systz_singleton);
178
179
        systz_singleton = NULL;
180
}
181
182
/*
183
 * Code to deal with the system timezone on all distros.
184
 * There's no dependency on the SystemTimezone GObject here.
185
 *
186
 * Here's what we know:
187
 *
188
 *  + /etc/localtime contains the binary data of the timezone.
189
 *    It can be a symlink to the actual data file, a hard link to the data
190
 *    file, or just a copy. So we can determine the timezone with this
191
 *    (reading the symlink, comparing inodes, or comparing content).
192
 *
193
 *  + However, most distributions also have the timezone setting
194
 *    configured somewhere else. This might be better to read it from there.
195
 *
196
 *    Debian/Ubuntu/Gentoo (new): content of /etc/timezone
197
 *    Fedora/Mandriva: the ZONE key in /etc/sysconfig/clock
198
 *    openSUSE: the TIMEZONE key in /etc/sysconfig/clock
199
 *    Solaris/OpenSolaris: the TZ key in /etc/TIMEZONE
200
 *    Arch Linux: the TIMEZONE key in /etc/rc.conf
201
 *    Gentoo (old): the ZONE key in /etc/conf.d/clock
202
 *
203
 *    FIXME: reading the system-tools-backends, it seems there's this too:
204
 *           Solaris: the TZ key in /etc/default/init
205
 *                    /etc/TIMEZONE seems to be a link to /etc/default/init
206
 *
207
 * First, some functions to handle those system config files.
208
 *
209
 */
210
211
/* This works for Debian and derivatives (including Ubuntu), and new Gentoo */
212
static char *
213
system_timezone_read_etc_timezone (void)
214
{
215
        FILE    *etc_timezone;
216
        GString *reading;
217
        int      c;
218
219
        etc_timezone = g_fopen (ETC_TIMEZONE, "r");
220
        if (!etc_timezone)
221
                return NULL;
222
223
        reading = g_string_new ("");
224
225
        c = fgetc (etc_timezone);
226
        /* only get the first line, we'll validate the value later */
227
        while (c != EOF && !g_ascii_isspace (c)) {
228
                reading = g_string_append_c (reading, c);
229
                c = fgetc (etc_timezone);
230
        }
231
232
        fclose (etc_timezone);
233
234
        if (reading->str && reading->str[0] != '\0')
235
                return g_string_free (reading, FALSE);
236
        else
237
                g_string_free (reading, TRUE);
238
239
        return NULL;
240
}
241
242
static gboolean
243
system_timezone_write_etc_timezone (const char  *tz,
244
                                    GError     **error)
245
{
246
        char     *content;
247
        GError   *our_error;
248
        gboolean  retval;
249
250
        if (!g_file_test (ETC_TIMEZONE, G_FILE_TEST_IS_REGULAR))
251
                return TRUE;
252
253
        content = g_strdup_printf ("%s\n", tz);
254
255
        our_error = NULL;
256
        retval = g_file_set_contents (ETC_TIMEZONE, content, -1, &our_error);
257
        g_free (content);
258
259
        if (!retval) {
260
                g_set_error (error, SYSTEM_TIMEZONE_ERROR,
261
                             SYSTEM_TIMEZONE_ERROR_GENERAL,
262
                             ETC_TIMEZONE" cannot be overwritten: %s",
263
                             our_error->message);
264
                g_error_free (our_error);
265
        }
266
267
        return retval;
268
}
269
270
271
/* Read a file that looks like a key-file (but there's no need for groups)
272
 * and get the last value for a specific key */
273
static char *
274
system_timezone_read_key_file (const char *filename,
275
                               const char *key)
276
{
277
        GIOChannel *channel;
278
        char       *key_eq;
279
        char       *line;
280
        char       *retval;
281
282
        if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
283
                return NULL;
284
285
        channel = g_io_channel_new_file (filename, "r", NULL);
286
        if (!channel)
287
                return NULL;
288
289
        key_eq = g_strdup_printf ("%s=", key);
290
        retval = NULL;
291
292
        while (g_io_channel_read_line (channel, &line, NULL,
293
                                       NULL, NULL) == G_IO_STATUS_NORMAL) {
294
                if (g_str_has_prefix (line, key_eq)) {
295
                        char *value;
296
                        int   len;
297
298
                        value = line + strlen (key_eq);
299
                        g_strstrip (value);
300
301
                        len = strlen (value);
302
303
                        if (value[0] == '\"') {
304
                                if (value[len - 1] == '\"') {
305
                                        if (retval)
306
                                                g_free (retval);
307
308
                                        retval = g_strndup (value + 1,
309
                                                            len - 2);
310
                                }
311
                        } else {
312
                                if (retval)
313
                                        g_free (retval);
314
315
                                retval = g_strdup (line + strlen (key_eq));
316
                        }
317
318
                        g_strstrip (retval);
319
                }
320
321
                g_free (line);
322
        }
323
324
        g_free (key_eq);
325
        g_io_channel_unref (channel);
326
327
        return retval;
328
}
329
330
static gboolean
331
system_timezone_write_key_file (const char  *filename,
332
                                const char  *key,
333
                                const char  *value,
334
                                GError     **error)
335
{
336
        GError    *our_error;
337
        char      *content;
338
        gsize      len;
339
        char      *key_eq;
340
        char     **lines;
341
        gboolean   replaced;
342
        gboolean   retval;
343
        int        n;
344
        
345
        if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
346
                return TRUE;
347
348
        our_error = NULL;
349
350
        if (!g_file_get_contents (filename, &content, &len, &our_error)) {
351
                g_set_error (error, SYSTEM_TIMEZONE_ERROR,
352
                             SYSTEM_TIMEZONE_ERROR_GENERAL,
353
                             "%s cannot be read: %s",
354
                             filename, our_error->message);
355
                g_error_free (our_error);
356
                return FALSE;
357
        }
358
359
        lines = g_strsplit (content, "\n", 0);
360
        g_free (content);
361
362
        key_eq = g_strdup_printf ("%s=", key);
363
        replaced = FALSE;
364
365
        for (n = 0; lines[n] != NULL; n++) {
366
                if (g_str_has_prefix (lines[n], key_eq)) {
367
                        char     *old_value;
368
                        gboolean  use_quotes;
369
370
                        old_value = lines[n] + strlen (key_eq);
371
                        g_strstrip (old_value);
372
                        use_quotes = old_value[0] == '\"';
373
374
                        g_free (lines[n]);
375
376
                        if (use_quotes)
377
                                lines[n] = g_strdup_printf ("%s\"%s\"",
378
                                                            key_eq, value);
379
                        else
380
                                lines[n] = g_strdup_printf ("%s%s",
381
                                                            key_eq, value);
382
383
                        replaced = TRUE;
384
                }
385
        }
386
387
        g_free (key_eq);
388
389
        if (!replaced) {
390
                g_strfreev (lines);
391
                return TRUE;
392
        }
393
394
        content = g_strjoinv ("\n", lines);
395
        g_strfreev (lines);
396
397
        retval = g_file_set_contents (filename, content, -1, &our_error);
398
        g_free (content);
399
400
        if (!retval) {
401
                g_set_error (error, SYSTEM_TIMEZONE_ERROR,
402
                             SYSTEM_TIMEZONE_ERROR_GENERAL,
403
                             "%s cannot be overwritten: %s",
404
                             filename, our_error->message);
405
                g_error_free (our_error);
406
        }
407
408
        return retval;
409
}
410
411
/* This works for Solaris/OpenSolaris */
412
static char *
413
system_timezone_read_etc_TIMEZONE (void)
414
{
415
        return system_timezone_read_key_file (ETC_TIMEZONE_MAJ,
416
                                              "TZ");
417
}
418
419
static gboolean
420
system_timezone_write_etc_TIMEZONE (const char  *tz,
421
                                    GError     **error)
422
{
423
        return system_timezone_write_key_file (ETC_TIMEZONE_MAJ,
424
                                               "TZ", tz, error);
425
}
426
427
/* This works for Fedora and Mandriva */
428
static char *
429
system_timezone_read_etc_sysconfig_clock (void)
430
{
431
        return system_timezone_read_key_file (ETC_SYSCONFIG_CLOCK,
432
                                              "ZONE");
433
}
434
435
static gboolean
436
system_timezone_write_etc_sysconfig_clock (const char  *tz,
437
                                           GError     **error)
438
{
439
        return system_timezone_write_key_file (ETC_SYSCONFIG_CLOCK,
440
                                               "ZONE", tz, error);
441
}
442
443
/* This works for openSUSE */
444
static char *
445
system_timezone_read_etc_sysconfig_clock_alt (void)
446
{
447
        return system_timezone_read_key_file (ETC_SYSCONFIG_CLOCK,
448
                                              "TIMEZONE");
449
}
450
451
static gboolean
452
system_timezone_write_etc_sysconfig_clock_alt (const char  *tz,
453
                                               GError     **error)
454
{
455
        return system_timezone_write_key_file (ETC_SYSCONFIG_CLOCK,
456
                                               "TIMEZONE", tz, error);
457
}
458
459
/* This works for old Gentoo */
460
static char *
461
system_timezone_read_etc_conf_d_clock (void)
462
{
463
        return system_timezone_read_key_file (ETC_CONF_D_CLOCK,
464
                                              "TIMEZONE");
465
}
466
467
static gboolean
468
system_timezone_write_etc_conf_d_clock (const char  *tz,
469
                                        GError     **error)
470
{
471
        return system_timezone_write_key_file (ETC_CONF_D_CLOCK,
472
                                               "TIMEZONE", tz, error);
473
}
474
475
/* This works for Arch Linux */
476
static char *
477
system_timezone_read_etc_rc_conf (void)
478
{
479
        return system_timezone_read_key_file (ETC_RC_CONF,
480
                                              "TIMEZONE");
481
}
482
483
static gboolean
484
system_timezone_write_etc_rc_conf (const char  *tz,
485
                                   GError     **error)
486
{
487
        return system_timezone_write_key_file (ETC_RC_CONF,
488
                                               "TIMEZONE", tz, error);
489
}
490
491
/*
492
 *
493
 * First, getting the timezone.
494
 *
495
 */
496
497
static char *
498
system_timezone_strip_path_if_valid (const char *filename)
499
{
500
        int skip;
501
502
        if (!filename || !g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/"))
503
                return NULL;
504
505
        /* Timezone data files also live under posix/ and right/ for some
506
         * reason.
507
         * FIXME: make sure accepting those files is valid. I think "posix" is
508
         * okay, not sure about "right" */
509
        if (g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/posix/"))
510
                skip = strlen (SYSTEM_ZONEINFODIR"/posix/");
511
        else if (g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/right/"))
512
                skip = strlen (SYSTEM_ZONEINFODIR"/right/");
513
        else
514
                skip = strlen (SYSTEM_ZONEINFODIR"/");
515
516
        return g_strdup (filename + skip);
517
}
518
519
/* Read the soft symlink from /etc/localtime */
520
static char *
521
system_timezone_read_etc_localtime_softlink (void)
522
{
523
        char *file;
524
        char *tz;
525
526
        if (!g_file_test (ETC_LOCALTIME, G_FILE_TEST_IS_SYMLINK))
527
                return NULL;
528
529
        file = g_file_read_link (ETC_LOCALTIME, NULL);
530
        tz = system_timezone_strip_path_if_valid (file);
531
        g_free (file);
532
533
        return tz;
534
}
535
536
typedef gboolean (*CompareFiles) (struct stat *a_stat,
537
                                  struct stat *b_stat,
538
                                  const char  *a_content,
539
                                  gsize        a_content_len,
540
                                  const char  *b_filename);
541
542
static char *
543
recursive_compare (struct stat  *localtime_stat,
544
                   const char   *localtime_content,
545
                   gsize         localtime_content_len,
546
                   char         *file,
547
                   CompareFiles  compare_func)
548
{
549
        struct stat file_stat;
550
551
        if (g_stat (file, &file_stat) != 0)
552
                return NULL;
553
554
        if (S_ISREG (file_stat.st_mode)) {
555
                if (compare_func (localtime_stat,
556
                                  &file_stat,
557
                                  localtime_content,
558
                                  localtime_content_len,
559
                                  file))
560
                        return system_timezone_strip_path_if_valid (file);
561
                else
562
                        return NULL;
563
        } else if (S_ISDIR (file_stat.st_mode)) {
564
                GDir       *dir = NULL;
565
                char       *ret = NULL;
566
                const char *subfile = NULL;
567
                char       *subpath = NULL;
568
569
                dir = g_dir_open (file, 0, NULL);
570
                if (dir == NULL)
571
                        return NULL;
572
573
                while ((subfile = g_dir_read_name (dir)) != NULL) {
574
                        subpath = g_build_filename (file, subfile, NULL);
575
576
                        ret = recursive_compare (localtime_stat,
577
                                                 localtime_content,
578
                                                 localtime_content_len,
579
                                                 subpath,
580
                                                 compare_func);
581
582
                        g_free (subpath);
583
584
                        if (ret != NULL)
585
                                break;
586
                }
587
588
                g_dir_close (dir);
589
590
                return ret;
591
        }
592
593
        return NULL;
594
}
595
596
597
static gboolean
598
files_are_identical_inode (struct stat *a_stat,
599
                           struct stat *b_stat,
600
                           const char  *a_content,
601
                           gsize        a_content_len,
602
                           const char  *b_filename)
603
{
604
        return (a_stat->st_ino == b_stat->st_ino);
605
}
606
607
608
/* Determine if /etc/localtime is a hard link to some file, by looking at
609
 * the inodes */
610
static char *
611
system_timezone_read_etc_localtime_hardlink (void)
612
{
613
        struct stat stat_localtime;
614
615
        if (g_stat (ETC_LOCALTIME, &stat_localtime) != 0)
616
                return NULL;
617
618
        if (!S_ISREG (stat_localtime.st_mode))
619
                return NULL;
620
621
        return recursive_compare (&stat_localtime,
622
                                  NULL,
623
                                  0,
624
                                  SYSTEM_ZONEINFODIR,
625
                                  files_are_identical_inode);
626
}
627
628
static gboolean
629
files_are_identical_content (struct stat *a_stat,
630
                             struct stat *b_stat,
631
                             const char  *a_content,
632
                             gsize        a_content_len,
633
                             const char  *b_filename)
634
{
635
        char  *b_content = NULL;
636
        gsize  b_content_len = -1;
637
        int    cmp;
638
639
        if (a_stat->st_size != b_stat->st_size)
640
                return FALSE;
641
642
        if (!g_file_get_contents (b_filename,
643
                                  &b_content, &b_content_len, NULL))
644
                return FALSE;
645
646
        if (a_content_len != b_content_len) {
647
                g_free (b_content);
648
                return FALSE;
649
        }
650
651
        cmp = memcmp (a_content, b_content, a_content_len);
652
        g_free (b_content);
653
654
        return (cmp == 0);
655
}
656
657
/* Determine if /etc/localtime is a copy of a timezone file */
658
static char *
659
system_timezone_read_etc_localtime_content (void)
660
{
661
        struct stat  stat_localtime;
662
        char        *localtime_content = NULL;
663
        gsize        localtime_content_len = -1;
664
        char        *retval;
665
666
        if (g_stat (ETC_LOCALTIME, &stat_localtime) != 0)
667
                return NULL;
668
669
        if (!S_ISREG (stat_localtime.st_mode))
670
                return NULL;
671
672
        if (!g_file_get_contents (ETC_LOCALTIME,
673
                                  &localtime_content,
674
                                  &localtime_content_len,
675
                                  NULL))
676
                return NULL;
677
678
        retval = recursive_compare (&stat_localtime,
679
                                   localtime_content,
680
                                   localtime_content_len,
681
                                   SYSTEM_ZONEINFODIR,
682
                                   files_are_identical_content);
683
684
        g_free (localtime_content);
685
686
        return retval;
687
}
688
689
typedef char * (*GetSystemTimezone) (void);
690
/* The order of the functions here define the priority of the methods used
691
 * to find the timezone. First method has higher priority. */
692
static GetSystemTimezone get_system_timezone_methods[] = {
693
        /* cheap and "more correct" than data from a config file */
694
        system_timezone_read_etc_localtime_softlink,
695
        /* reading various config files */
696
        system_timezone_read_etc_timezone,
697
        system_timezone_read_etc_sysconfig_clock,
698
        system_timezone_read_etc_sysconfig_clock_alt,
699
        system_timezone_read_etc_TIMEZONE,
700
        system_timezone_read_etc_rc_conf,
701
        /* reading deprecated config files */
702
        system_timezone_read_etc_conf_d_clock,
703
        /* reading /etc/timezone directly. Expensive since we have to stat
704
         * many files */
705
        system_timezone_read_etc_localtime_hardlink,
706
        system_timezone_read_etc_localtime_content,
707
        NULL
708
};
709
710
static gboolean
711
system_timezone_is_valid (const char *tz)
712
{
713
        const char *c;
714
715
        if (!tz)
716
                return FALSE;
717
718
        for (c = tz; *c != '\0'; c++) {
719
                if (!(g_ascii_isalnum (*c) ||
720
                      *c == '/' || *c == '-' || *c == '_'))
721
                        return FALSE;
722
        }
723
724
        return TRUE;
725
}
726
727
char *
728
system_timezone_find (void)
729
{
730
        char *tz;
731
        int   i;
732
733
        for (i = 0; get_system_timezone_methods[i] != NULL; i++) {
734
                tz = get_system_timezone_methods[i] ();
735
736
                if (system_timezone_is_valid (tz))
737
                        return tz;
738
739
                g_free (tz);
740
        }
741
742
        return g_strdup ("UTC");
743
}
744
745
/*
746
 *
747
 * Now, setting the timezone.
748
 *
749
 */
750
751
static gboolean
752
system_timezone_is_zone_file_valid (const char  *zone_file,
753
                                    GError     **error)
754
{
755
        GError     *our_error;
756
        GIOChannel *channel;
757
        char        buffer[strlen (TZ_MAGIC)];
758
        gsize       read;
759
760
        /* First, check the zone_file is properly rooted */
761
        if (!g_str_has_prefix (zone_file, SYSTEM_ZONEINFODIR"/")) {
762
                g_set_error (error, SYSTEM_TIMEZONE_ERROR,
763
                             SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE,
764
                             "Timezone file needs to be under "SYSTEM_ZONEINFODIR);
765
                return FALSE;
766
        }
767
768
        /* Second, check it's a regular file that exists */
769
        if (!g_file_test (zone_file, G_FILE_TEST_IS_REGULAR)) {
770
                g_set_error (error, SYSTEM_TIMEZONE_ERROR,
771
                             SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE,
772
                             "No such timezone file %s", zone_file);
773
                return FALSE;
774
        }
775
776
        /* Third, check that it's a tzfile (see tzfile(5)). The file has a 4
777
         * bytes header which is TZ_MAGIC.
778
         *
779
         * TODO: is there glibc API for this? */
780
        our_error = NULL;
781
        channel = g_io_channel_new_file (zone_file, "r", &our_error);
782
        if (!our_error)
783
                g_io_channel_read_chars (channel,
784
                                         buffer, strlen (TZ_MAGIC),
785
                                         &read, &our_error);
786
        if (channel)
787
                g_io_channel_unref (channel);
788
789
        if (our_error) {
790
                g_set_error (error, SYSTEM_TIMEZONE_ERROR,
791
                             SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE,
792
                             "Timezone file %s cannot be read: %s",
793
                             zone_file, our_error->message);
794
                g_error_free (our_error);
795
                return FALSE;
796
        }
797
798
        if (read != strlen (TZ_MAGIC) || strncmp (buffer, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
799
                g_set_error (error, SYSTEM_TIMEZONE_ERROR,
800
                             SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE,
801
                             "%s is not a timezone file",
802
                             zone_file);
803
                return FALSE;
804
        }
805
806
        return TRUE;
807
}
808
809
static gboolean
810
system_timezone_set_etc_timezone (const char  *zone_file,
811
                                  GError     **error)
812
{
813
        GError *our_error;
814
        char   *content;
815
        gsize   len;
816
817
        if (!system_timezone_is_zone_file_valid (zone_file, error))
818
                return FALSE;
819
820
        /* If /etc/localtime is a symlink, write a symlink */
821
        if (g_file_test (ETC_LOCALTIME, G_FILE_TEST_IS_SYMLINK)) {
822
                if (g_unlink (ETC_LOCALTIME) == 0 &&
823
                    symlink (zone_file, ETC_LOCALTIME) == 0)
824
                        return TRUE;
825
826
                /* If we couldn't symlink the file, we'll just fallback on
827
                 * copying it */
828
        }
829
830
        /* Else copy the file to /etc/localtime. We explicitly avoid doing
831
         * hard links since they break with different partitions */
832
        our_error = NULL;
833
        if (!g_file_get_contents (zone_file, &content, &len, &our_error)) {
834
                g_set_error (error, SYSTEM_TIMEZONE_ERROR,
835
                             SYSTEM_TIMEZONE_ERROR_GENERAL,
836
                             "Timezone file %s cannot be read: %s",
837
                             zone_file, our_error->message);
838
                g_error_free (our_error);
839
                return FALSE;
840
        }
841
842
        if (!g_file_set_contents (ETC_LOCALTIME, content, len, &our_error)) {
843
                g_set_error (error, SYSTEM_TIMEZONE_ERROR,
844
                             SYSTEM_TIMEZONE_ERROR_GENERAL,
845
                             ETC_LOCALTIME" cannot be overwritten: %s",
846
                             our_error->message);
847
                g_error_free (our_error);
848
                g_free (content);
849
                return FALSE;
850
        }
851
852
        g_free (content);
853
854
        return TRUE;
855
}
856
857
typedef gboolean (*SetSystemTimezone) (const char  *tz,
858
                                       GError     **error);
859
/* The order here does not matter too much: we'll try to change all files
860
 * that already have a timezone configured. It matters in case of error,
861
 * since the process will be stopped and the last methods won't be called.
862
 * So we use the same order as in get_system_timezone_methods */
863
static SetSystemTimezone set_system_timezone_methods[] = {
864
        /* writing various config files if they exist and have the
865
         * setting already present */
866
        system_timezone_write_etc_timezone,
867
        system_timezone_write_etc_sysconfig_clock,
868
        system_timezone_write_etc_sysconfig_clock_alt,
869
        system_timezone_write_etc_TIMEZONE,
870
        system_timezone_write_etc_rc_conf,
871
        /* writing deprecated config files if they exist and have the
872
         * setting already present */
873
        system_timezone_write_etc_conf_d_clock,
874
        NULL
875
};
876
877
static gboolean
878
system_timezone_update_config (const char  *tz,
879
                               GError     **error)
880
{
881
        int i;
882
883
        for (i = 0; set_system_timezone_methods[i] != NULL; i++) {
884
                if (!set_system_timezone_methods[i] (tz, error))
885
                        return FALSE;
886
                /* FIXME: maybe continue to change all config files if
887
                 * possible? */
888
        }
889
890
        return TRUE;
891
}
892
893
gboolean
894
system_timezone_set (const char  *tz,
895
                     GError     **error)
896
{
897
        char     *zone_file;
898
        gboolean  retval;
899
900
        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
901
902
        zone_file = g_build_filename (SYSTEM_ZONEINFODIR, tz, NULL);
903
904
        /* FIXME: is it right to return FALSE even when /etc/localtime was
905
         * changed but not the config files? */
906
        retval = system_timezone_set_etc_timezone (zone_file, error) &&
907
                 system_timezone_update_config (tz, error);
908
909
        g_free (zone_file);
910
911
        return retval;
912
}
913
914
GQuark
915
system_timezone_error_quark (void)
916
{
917
        static GQuark ret = 0;
918
919
        if (ret == 0) {
920
                ret = g_quark_from_static_string ("system-timezone-error");
921
        }
922
923
        return ret;
924
}
(-)a/plugins/datetime/system-timezone.h (+80 lines)
Line 0 Link Here
1
/* System timezone handling
2
 *
3
 * Copyright (C) 2008 Novell, Inc.
4
 *
5
 * Authors: Vincent Untz <vuntz@gnome.org>
6
 * 
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
 */
21
22
#ifndef __SYSTEM_TIMEZONE_H__
23
#define __SYSTEM_TIMEZONE_H__
24
25
#include <glib.h>
26
#include <glib-object.h>
27
28
G_BEGIN_DECLS
29
30
#ifdef HAVE_SOLARIS
31
#define SYSTEM_ZONEINFODIR "/usr/share/lib/zoneinfo/tab"
32
#else
33
#define SYSTEM_ZONEINFODIR "/usr/share/zoneinfo"
34
#endif
35
36
37
#define SYSTEM_TIMEZONE_TYPE         (system_timezone_get_type ())
38
#define SYSTEM_TIMEZONE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezone))
39
#define SYSTEM_TIMEZONE_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), SYSTEM_TIMEZONE_TYPE, SystemTimezoneClass))
40
#define IS_SYSTEM_TIMEZONE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), SYSTEM_TIMEZONE_TYPE))
41
#define IS_SYSTEM_TIMEZONE_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), SYSTEM_TIMEZONE_TYPE))
42
#define SYSTEM_TIMEZONE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezoneClass))
43
44
typedef struct
45
{
46
        GObject g_object;
47
} SystemTimezone;
48
49
typedef struct
50
{
51
        GObjectClass g_object_class;
52
} SystemTimezoneClass;
53
54
GType system_timezone_get_type (void);
55
56
SystemTimezone *system_timezone_new (void);
57
58
const char *system_timezone_get (SystemTimezone *systz);
59
const char *system_timezone_get_env (SystemTimezone *systz);
60
61
/* Functions to set the timezone. They won't be used by the applet, but
62
 * by a program with more privileges */
63
64
#define SYSTEM_TIMEZONE_ERROR system_timezone_error_quark ()
65
GQuark system_timezone_error_quark (void);
66
67
typedef enum
68
{
69
        SYSTEM_TIMEZONE_ERROR_GENERAL,
70
        SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE,
71
        SYSTEM_TIMEZONE_NUM_ERRORS
72
} SystemTimezoneError;
73
74
char *system_timezone_find (void);
75
76
gboolean system_timezone_set (const char  *tz,
77
                              GError     **error);
78
79
G_END_DECLS
80
#endif /* __SYSTEM_TIMEZONE_H__ */
(-)a/plugins/datetime/test-system-timezone.c (-1 / +93 lines)
Line 0 Link Here
0
- 
1
/* Test for system timezone handling
2
 *
3
 * Copyright (C) 2008-2010 Novell, Inc.
4
 *
5
 * Authors: Vincent Untz <vuntz@gnome.org>
6
 * 
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
 */
21
22
#include <glib.h>
23
#include "system-timezone.h"
24
25
static void
26
timezone_print (void)
27
{
28
	SystemTimezone *systz;
29
30
	systz = system_timezone_new ();
31
        g_print ("Current timezone: %s\n", system_timezone_get (systz));
32
	g_object_unref (systz);
33
}
34
35
static int
36
timezone_set (const char *new_tz)
37
{
38
        GError *error;
39
40
        error = NULL;
41
        if (!system_timezone_set (new_tz, &error)) {
42
                g_printerr ("%s\n", error->message);
43
                g_error_free (error);
44
                return 1;
45
        }
46
47
	return 0;
48
}
49
50
int
51
main (int    argc,
52
      char **argv)
53
{
54
	int      retval;
55
56
	gboolean  get = FALSE;
57
	char     *tz_set = NULL;
58
59
	GError         *error;
60
	GOptionContext *context;
61
        GOptionEntry options[] = {
62
                { "get", 'g', 0, G_OPTION_ARG_NONE, &get, "Get the current timezone", NULL },
63
                { "set", 's', 0, G_OPTION_ARG_STRING, &tz_set, "Set the timezone to TIMEZONE", "TIMEZONE" },
64
                { NULL, 0, 0, 0, NULL, NULL, NULL }
65
        };
66
67
	retval = 0;
68
69
	g_type_init ();
70
71
	context = g_option_context_new ("");
72
	g_option_context_add_main_entries (context, options, NULL);
73
74
	error = NULL;
75
	if (!g_option_context_parse (context, &argc, &argv, &error)) {
76
		g_printerr ("%s\n", error->message);
77
		g_error_free (error);
78
		g_option_context_free (context);
79
80
		return 1;
81
	}
82
83
	g_option_context_free (context);
84
85
	if (get || (!tz_set))
86
		timezone_print ();
87
	else if (tz_set)
88
		retval = timezone_set (tz_set);
89
	else
90
		g_assert_not_reached ();
91
92
        return retval;
93
}

Return to bug 796055