timedated.c revision 7fd1b19bc9e9f5574f2877936b8ac267c7706947
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann This file is part of systemd.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann Copyright 2011 Lennart Poettering
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann systemd is free software; you can redistribute it and/or modify it
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann under the terms of the GNU Lesser General Public License as published by
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann the Free Software Foundation; either version 2.1 of the License, or
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann (at your option) any later version.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann systemd is distributed in the hope that it will be useful, but
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann WITHOUT ANY WARRANTY; without even the implied warranty of
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann Lesser General Public License for more details.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann You should have received a copy of the GNU Lesser General Public License
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann along with systemd; If not, see <http://www.gnu.org/licenses/>.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <interface name=\"org.freedesktop.timedate1\">\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <property name=\"Timezone\" type=\"s\" access=\"read\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <property name=\"LocalRTC\" type=\"b\" access=\"read\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <property name=\"CanNTP\" type=\"b\" access=\"read\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <property name=\"NTP\" type=\"b\" access=\"read\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <method name=\"SetTime\">\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <arg name=\"usec_utc\" type=\"x\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <arg name=\"relative\" type=\"b\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " </method>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <method name=\"SetTimezone\">\n" \
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering " <arg name=\"timezone\" type=\"s\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " </method>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <method name=\"SetLocalRTC\">\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <arg name=\"local_rtc\" type=\"b\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <arg name=\"fix_system\" type=\"b\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " </method>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <method name=\"SetNTP\">\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <arg name=\"use_ntp\" type=\"b\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann " </method>\n" \
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering " </interface>\n"
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannconst char timedate_interface[] _introspect_("timedate1") = INTERFACE;
e23f4bb525991c5908be0d0e7f8374c964d9996cDavid Herrmanntypedef struct TZ {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void free_data(void) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic bool valid_timezone(const char *name) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *p;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann bool slash = false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (p = name; *p; p++) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (*p == '/') {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int read_data(void) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/.");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_warning("Failed to get target of /etc/localtime: %s", strerror(-r));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *e;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann e = path_startswith(t, "/usr/share/zoneinfo/");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann e = path_startswith(t, "../usr/share/zoneinfo/");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/.");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (unlink("/etc/localtime") < 0 && errno != ENOENT)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann p = strappend("../usr/share/zoneinfo/", tz.zone);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int write_data_local_rtc(void) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = read_full_file("/etc/adjtime", &s, NULL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann w = new(char, a + (tz.local_rtc ? 5 : 3) + b + 1);
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann *(char*) mempcpy(stpcpy(mempcpy(w, s, a), tz.local_rtc ? "LOCAL" : "UTC"), e, b) = 0;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return write_string_file_atomic_label("/etc/adjtime", w);
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmannstatic char** get_ntp_services(void) {
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann _cleanup_strv_free_ char **r = NULL, **files;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("Failed to read NTP units file: %m");
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann if (l[0] == 0 || l[0] == '#')
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (strv_extend(&r, l) < 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann char **i, **l;
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering const char *s;
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering "org.freedesktop.systemd1.Manager",
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann "GetUnitFileState");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (streq(error.name, "org.freedesktop.DBus.Error.FileNotFound")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* This implementation does not exist, try next one */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("Failed to issue method call: %s", bus_error_message(&error));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("Failed to parse reply: %s", bus_error_message(&error));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* NTP is not installed. */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int start_ntp(DBusConnection *bus, DBusError *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann char **i, **l;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann "org.freedesktop.systemd1.Manager",
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("Could not append arguments to message.");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann if (streq(error->name, "org.freedesktop.DBus.Error.FileNotFound") ||
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann streq(error->name, "org.freedesktop.systemd1.LoadFailed") ||
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann streq(error->name, "org.freedesktop.systemd1.NoSuchUnit")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* This implementation does not exist, try next one */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("Failed to issue method call: %s", bus_error_message(error));
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann /* No implementaiton available... */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int enable_ntp(DBusConnection *bus, DBusError *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann char **i, **l;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann "org.freedesktop.systemd1.Manager",
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann tz.use_ntp ? "EnableUnitFiles" : "DisableUnitFiles");
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann /* send runtime bool */
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &f)) {
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann log_error("Failed to append runtime boolean.");
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann /* send force bool */
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &t)) {
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann log_error("Failed to append force boolean.");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (streq(error->name, "org.freedesktop.DBus.Error.FileNotFound")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* This implementation does not exist, try next one */
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann log_error("Failed to issue method call: %s", bus_error_message(error));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann "org.freedesktop.systemd1.Manager",
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann log_error("Failed to issue method call: %s", bus_error_message(error));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int property_append_can_ntp(DBusMessageIter *i, const char *property, void *data) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int property_append_ntp(DBusMessageIter *i, const char *property, void *data) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic const BusProperty bus_timedate_properties[] = {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann { "Timezone", bus_property_append_string, "s", offsetof(TZ, zone), true },
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann { "LocalRTC", bus_property_append_bool, "b", offsetof(TZ, local_rtc) },
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann { "CanNTP", property_append_can_ntp, "b", offsetof(TZ, can_ntp) },
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann { "NTP", property_append_ntp, "b", offsetof(TZ, use_ntp) },
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann { "org.freedesktop.timedate1", bus_timedate_properties, &tz },
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic DBusHandlerResult timedate_message_handler(
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering DBusMessage *reply = NULL, *changed = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTimezone")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann const char *z;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, &error, -EINVAL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, NULL, -EINVAL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-timezone", interactive, NULL, &error);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, &error, r);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* 1. Write new configuration file */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("Failed to set timezone: %s", strerror(-r));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, NULL, r);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* 2. Tell the kernel our time zone */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* 3. Sync RTC from system clock, with the new delta */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann "MESSAGE=Changed timezone to '%s'.", tz.zone,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann "Timezone\0");
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetLocalRTC")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, &error, -EINVAL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-local-rtc", interactive, NULL, &error);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, &error, r);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* 1. Write new configuration file */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("Failed to set RTC to local/UTC: %s", strerror(-r));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, NULL, r);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* 2. Tell the kernel our time zone */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* 3. Synchronize clocks */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Sync system clock from RTC; first,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * initialize the timezone fields of
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * struct tm. */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Override the main fields of
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * struct tm, but not the timezone
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* And set the system clock
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * with this */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Sync RTC from system clock */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_info("RTC configured to %s time.", tz.local_rtc ? "local" : "UTC");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann "LocalRTC\0");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTime")) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, &error, -EINVAL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, NULL, -EINVAL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if ((utc > 0 && x < n) ||
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann (utc < 0 && x > n))
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering return bus_send_error_reply(connection, message, NULL, -EOVERFLOW);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-time", interactive, NULL, &error);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, &error, r);
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering /* Set system clock */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return bus_send_error_reply(connection, message, NULL, -errno);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Sync down to RTC */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann "REALTIME=%llu", (unsigned long long) timespec_load(&ts),
NULL);
if (!dbus_message_get_args(
&error,
r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-ntp", interactive, NULL, &error);
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
if (!changed)
goto oom;
goto oom;
goto oom;
if (changed) {
goto oom;
return DBUS_HANDLER_RESULT_HANDLED;
oom:
if (reply)
if (changed)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
if (!bus) {
r = -ECONNREFUSED;
goto fail2;
if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL) ||
r = log_oom();
goto fail;
r = -EEXIST;
goto fail;
if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
r = -EEXIST;
goto fail;
if (_bus)
fail:
bool exiting = false;
log_open();
r = -EINVAL;
goto finish;
r = read_data();
goto finish;
goto finish;
goto finish;
if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)))
exiting = true;
free_data();
if (bus) {