- assert(connection);
- assert(message);
-
- dbus_error_init(&error);
-
- if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTimezone")) {
- const char *z;
- dbus_bool_t interactive;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &z,
- DBUS_TYPE_BOOLEAN, &interactive,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- if (!valid_timezone(z))
- return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
- if (!streq_ptr(z, tz.zone)) {
- char *t;
-
- r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-timezone", interactive, NULL, &error);
- if (r < 0)
- return bus_send_error_reply(connection, message, &error, r);
-
- t = strdup(z);
- if (!t)
- goto oom;
-
- free(tz.zone);
- tz.zone = t;
-
- /* 1. Write new configuration file */
- r = write_data_timezone();
- if (r < 0) {
- log_error("Failed to set timezone: %s", strerror(-r));
- return bus_send_error_reply(connection, message, NULL, r);
- }
-
- /* 2. Tell the kernel our timezone */
- hwclock_set_timezone(NULL);
-
- if (tz.local_rtc) {
- struct timespec ts;
- struct tm *tm;
-
- /* 3. Sync RTC from system clock, with the new delta */
- assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
- assert_se(tm = localtime(&ts.tv_sec));
- hwclock_set_time(tm);
- }
-
- log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_TIMEZONE_CHANGE),
- "TIMEZONE=%s", tz.zone,
- "MESSAGE=Changed timezone to '%s'.", tz.zone,
- NULL);
-
- changed = bus_properties_changed_new(
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
- "Timezone\0");
- if (!changed)
- goto oom;
- }
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetLocalRTC")) {
- dbus_bool_t lrtc;
- dbus_bool_t fix_system;
- dbus_bool_t interactive;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_BOOLEAN, &lrtc,
- DBUS_TYPE_BOOLEAN, &fix_system,
- DBUS_TYPE_BOOLEAN, &interactive,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- if (lrtc != tz.local_rtc) {
- struct timespec ts;
-
- r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-local-rtc", interactive, NULL, &error);
- if (r < 0)
- return bus_send_error_reply(connection, message, &error, r);
-
- tz.local_rtc = lrtc;
-
- /* 1. Write new configuration file */
- r = write_data_local_rtc();
- if (r < 0) {
- log_error("Failed to set RTC to local/UTC: %s", strerror(-r));
- return bus_send_error_reply(connection, message, NULL, r);
- }
-
- /* 2. Tell the kernel our timezone */
- hwclock_set_timezone(NULL);
-
- /* 3. Synchronize clocks */
- assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
-
- if (fix_system) {
- struct tm tm;
-
- /* Sync system clock from RTC; first,
- * initialize the timezone fields of
- * struct tm. */
- if (tz.local_rtc)
- tm = *localtime(&ts.tv_sec);
- else
- tm = *gmtime(&ts.tv_sec);
-
- /* Override the main fields of
- * struct tm, but not the timezone
- * fields */
- if (hwclock_get_time(&tm) >= 0) {
-
- /* And set the system clock
- * with this */
- if (tz.local_rtc)
- ts.tv_sec = mktime(&tm);
- else
- ts.tv_sec = timegm(&tm);
-
- clock_settime(CLOCK_REALTIME, &ts);
- }
-
- } else {
- struct tm *tm;
-
- /* Sync RTC from system clock */
- if (tz.local_rtc)
- tm = localtime(&ts.tv_sec);
- else
- tm = gmtime(&ts.tv_sec);
-
- hwclock_set_time(tm);
- }
-
- log_info("RTC configured to %s time.", tz.local_rtc ? "local" : "UTC");
-
- changed = bus_properties_changed_new(
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
- "LocalRTC\0");
- if (!changed)
- goto oom;
- }