]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/timedate/timedatectl.c
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
[thirdparty/systemd.git] / src / timedate / timedatectl.c
index 74f40b9c80082c4027dbee5cca937319a79bf7d5..b6fa45869600f55fcdf743a77c1212c1e715486e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
-#include <stdbool.h>
-#include <unistd.h>
 #include <getopt.h>
 #include <locale.h>
-#include <string.h>
-#include <sys/timex.h>
+#include <stdbool.h>
+#include <stdlib.h>
 
 #include "sd-bus.h"
-#include "bus-util.h"
+
 #include "bus-error.h"
-#include "util.h"
+#include "bus-util.h"
+#include "pager.h"
+#include "parse-util.h"
 #include "spawn-polkit-agent.h"
-#include "build.h"
 #include "strv.h"
-#include "pager.h"
-#include "time-dst.h"
+#include "terminal-util.h"
+#include "util.h"
 
 static bool arg_no_pager = false;
 static bool arg_ask_password = true;
@@ -76,62 +74,49 @@ typedef struct StatusInfo {
         bool ntp_synced;
 } StatusInfo;
 
-static const char *jump_str(int delta_minutes, char *s, size_t size) {
-        if (delta_minutes == 60)
-                return "one hour forward";
-        if (delta_minutes == -60)
-                return "one hour backwards";
-        if (delta_minutes < 0) {
-                snprintf(s, size, "%i minutes backwards", -delta_minutes);
-                return s;
+static void status_info_clear(StatusInfo *info) {
+        if (info) {
+                free(info->timezone);
+                zero(*info);
         }
-        if (delta_minutes > 0) {
-                snprintf(s, size, "%i minutes forward", delta_minutes);
-                return s;
-        }
-        return "";
 }
 
 static void print_status_info(const StatusInfo *i) {
         char a[FORMAT_TIMESTAMP_MAX];
-        char b[FORMAT_TIMESTAMP_MAX];
-        char s[32];
         struct tm tm;
         time_t sec;
         bool have_time = false;
-        _cleanup_free_ char *zc = NULL, *zn = NULL;
-        time_t t, tc, tn;
-        int dn = 0;
-        bool is_dstc = false, is_dstn = false;
+        const char *old_tz = NULL, *tz;
         int r;
 
         assert(i);
 
-        /* Enforce the values of /etc/localtime */
-        if (getenv("TZ")) {
-                fprintf(stderr, "Warning: Ignoring the TZ variable. Reading the system's time zone setting only.\n\n");
-                unsetenv("TZ");
-        }
+        /* Save the old $TZ */
+        tz = getenv("TZ");
+        if (tz)
+                old_tz = strdupa(tz);
+
+        /* Set the new $TZ */
+        if (setenv("TZ", isempty(i->timezone) ? "UTC" : i->timezone, true) < 0)
+                log_warning_errno(errno, "Failed to set TZ environment variable, ignoring: %m");
+        else
+                tzset();
 
         if (i->time != 0) {
                 sec = (time_t) (i->time / USEC_PER_SEC);
                 have_time = true;
-        } else if (arg_transport == BUS_TRANSPORT_LOCAL) {
+        } else if (IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
                 sec = time(NULL);
                 have_time = true;
         } else
-                fprintf(stderr, "Warning: Could not get time from timedated and not operating locally.\n\n");
+                log_warning("Could not get time from timedated and not operating locally, ignoring.");
 
         if (have_time) {
-                zero(tm);
-                assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) > 0);
-                char_array_0(a);
-                printf("      Local time: %s\n", a);
-
-                zero(tm);
-                assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)) > 0);
-                char_array_0(a);
-                printf("  Universal time: %s\n", a);
+                xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm));
+                printf("      Local time: %.*s\n", (int) sizeof(a), a);
+
+                xstrftime(a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm));
+                printf("  Universal time: %.*s\n", (int) sizeof(a), a);
         } else {
                 printf("      Local time: %s\n", "n/a");
                 printf("  Universal time: %s\n", "n/a");
@@ -140,78 +125,46 @@ static void print_status_info(const StatusInfo *i) {
         if (i->rtc_time > 0) {
                 time_t rtc_sec;
 
-                rtc_sec = (time_t)(i->rtc_time / USEC_PER_SEC);
-                zero(tm);
-                assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm)) > 0);
-                char_array_0(a);
-                printf("        RTC time: %s\n", a);
+                rtc_sec = (time_t) (i->rtc_time / USEC_PER_SEC);
+                xstrftime(a, "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm));
+                printf("        RTC time: %.*s\n", (int) sizeof(a), a);
         } else
                 printf("        RTC time: %s\n", "n/a");
 
-        if (have_time) {
-                zero(tm);
-                assert_se(strftime(a, sizeof(a), "%Z, %z", localtime_r(&sec, &tm)) > 0);
-                char_array_0(a);
-        }
+        if (have_time)
+                xstrftime(a, "%Z, %z", localtime_r(&sec, &tm));
 
-        printf("       Time zone: %s (%s)\n"
-               "     NTP enabled: %s\n"
+        /* Restore the $TZ */
+        if (old_tz)
+                r = setenv("TZ", old_tz, true);
+        else
+                r = unsetenv("TZ");
+        if (r < 0)
+                log_warning_errno(errno, "Failed to set TZ environment variable, ignoring: %m");
+        else
+                tzset();
+
+        printf("       Time zone: %s (%.*s)\n"
+               " Network time on: %s\n"
                "NTP synchronized: %s\n"
                " RTC in local TZ: %s\n",
-               strna(i->timezone), have_time ? a : "n/a",
+               strna(i->timezone), (int) sizeof(a), have_time ? a : "n/a",
                i->ntp_capable ? yes_no(i->ntp_enabled) : "n/a",
                yes_no(i->ntp_synced),
                yes_no(i->rtc_local));
 
-        if (have_time) {
-                r = time_get_dst(sec, "/etc/localtime",
-                                 &tc, &zc, &is_dstc,
-                                 &tn, &dn, &zn, &is_dstn);
-                if (r < 0)
-                        printf("      DST active: %s\n", "n/a");
-                else {
-                        printf("      DST active: %s\n", yes_no(is_dstc));
-
-                        t = tc - 1;
-                        zero(tm);
-                        assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
-                        char_array_0(a);
-
-                        zero(tm);
-                        assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm)) > 0);
-                        char_array_0(b);
-                        printf(" Last DST change: DST %s at\n"
-                               "                  %s\n"
-                               "                  %s\n",
-                               is_dstc ? "began" : "ended", a, b);
-
-                        t = tn - 1;
-                        zero(tm);
-                        assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
-                        char_array_0(a);
-
-                        zero(tm);
-                        assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm)) > 0);
-                        char_array_0(b);
-                        printf(" Next DST change: DST %s (the clock jumps %s) at\n"
-                               "                  %s\n"
-                               "                  %s\n",
-                               is_dstn ? "begins" : "ends", jump_str(dn, s, sizeof(s)), a, b);
-                }
-        } else
-                printf("      DST active: %s\n", yes_no(is_dstc));
-
         if (i->rtc_local)
-                fputs("\n" ANSI_HIGHLIGHT_ON
-                      "Warning: The system is configured to read the RTC time in the local time zone. This\n"
-                      "         mode can not be fully supported. It will create various problems with time\n"
-                      "         zone changes and daylight saving time adjustments. The RTC time is never updated,\n"
-                      "         it relies on external facilities to maintain it. If at all possible, use\n"
-                      "         RTC in UTC by calling 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout);
+                fputs("\n" ANSI_HIGHLIGHT
+                      "Warning: The system is configured to read the RTC time in the local time zone.\n"
+                      "         This mode can not be fully supported. It will create various problems\n"
+                      "         with time zone changes and daylight saving time adjustments. The RTC\n"
+                      "         time is never updated, it relies on external facilities to maintain it.\n"
+                      "         If at all possible, use RTC in UTC by calling\n"
+                      "         'timedatectl set-local-rtc 0'." ANSI_NORMAL "\n", stdout);
 }
 
 static int show_status(sd_bus *bus, char **args, unsigned n) {
-        StatusInfo info = {};
+        _cleanup_(status_info_clear) StatusInfo info = {};
         static const struct bus_properties_map map[]  = {
                 { "Timezone",        "s", NULL, offsetof(StatusInfo, timezone) },
                 { "LocalRTC",        "b", NULL, offsetof(StatusInfo, rtc_local) },
@@ -231,20 +184,16 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
                                    "/org/freedesktop/timedate1",
                                    map,
                                    &info);
-        if (r < 0) {
-                log_error_errno(r, "Failed to query server: %m");
-                goto fail;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to query server: %m");
 
         print_status_info(&info);
 
-fail:
-        free(info.timezone);
         return r;
 }
 
 static int set_time(sd_bus *bus, char **args, unsigned n) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         bool relative = false, interactive = arg_ask_password;
         usec_t t;
         int r;
@@ -275,7 +224,7 @@ static int set_time(sd_bus *bus, char **args, unsigned n) {
 }
 
 static int set_timezone(sd_bus *bus, char **args, unsigned n) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
 
         assert(args);
@@ -298,7 +247,7 @@ static int set_timezone(sd_bus *bus, char **args, unsigned n) {
 }
 
 static int set_local_rtc(sd_bus *bus, char **args, unsigned n) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r, b;
 
         assert(args);
@@ -327,7 +276,7 @@ static int set_local_rtc(sd_bus *bus, char **args, unsigned n) {
 }
 
 static int set_ntp(sd_bus *bus, char **args, unsigned n) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int b, r;
 
         assert(args);
@@ -388,7 +337,7 @@ static void help(void) {
                "  set-timezone ZONE        Set system time zone\n"
                "  list-timezones           Show known time zones\n"
                "  set-local-rtc BOOL       Control whether RTC is in local time\n"
-               "  set-ntp BOOL             Control whether NTP is enabled\n",
+               "  set-ntp BOOL             Enable or disable network time synchronization\n",
                program_invocation_short_name);
 }
 
@@ -426,9 +375,7 @@ static int parse_argv(int argc, char *argv[]) {
                         return 0;
 
                 case ARG_VERSION:
-                        puts(PACKAGE_STRING);
-                        puts(SYSTEMD_FEATURES);
-                        return 0;
+                        return version();
 
                 case 'H':
                         arg_transport = BUS_TRANSPORT_REMOTE;
@@ -543,7 +490,7 @@ static int timedatectl_main(sd_bus *bus, int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
-        _cleanup_bus_close_unref_ sd_bus *bus = NULL;
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;
 
         setlocale(LC_ALL, "");
@@ -554,7 +501,7 @@ int main(int argc, char *argv[]) {
         if (r <= 0)
                 goto finish;
 
-        r = bus_open_transport(arg_transport, arg_host, false, &bus);
+        r = bus_connect_transport(arg_transport, arg_host, false, &bus);
         if (r < 0) {
                 log_error_errno(r, "Failed to create bus connection: %m");
                 goto finish;