]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/time-util.c
tree-wide: drop license boilerplate
[thirdparty/systemd.git] / src / basic / time-util.c
index 00979bfe594a7b2b05973002683790afa93fb528..f7067e9d0c03dff436377207721564211db13777 100644 (file)
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
   Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
 #include <errno.h>
@@ -37,6 +25,7 @@
 #include "macro.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "process-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
@@ -849,11 +838,11 @@ parse_usec:
         }
 
 from_tm:
-        x = mktime_or_timegm(&tm, utc);
-        if (x < 0)
+        if (weekday >= 0 && tm.tm_wday != weekday)
                 return -EINVAL;
 
-        if (weekday >= 0 && tm.tm_wday != weekday)
+        x = mktime_or_timegm(&tm, utc);
+        if (x < 0)
                 return -EINVAL;
 
         ret = (usec_t) x * USEC_PER_SEC + x_usec;
@@ -883,49 +872,47 @@ typedef struct ParseTimestampResult {
 } ParseTimestampResult;
 
 int parse_timestamp(const char *t, usec_t *usec) {
-        char *last_space, *timezone = NULL;
+        char *last_space, *tz = NULL;
         ParseTimestampResult *shared, tmp;
         int r;
-        pid_t pid;
 
         last_space = strrchr(t, ' ');
         if (last_space != NULL && timezone_is_valid(last_space + 1))
-                timezone = last_space + 1;
+                tz = last_space + 1;
 
-        if (timezone == NULL || endswith_no_case(t, " UTC"))
+        if (!tz || endswith_no_case(t, " UTC"))
                 return parse_timestamp_impl(t, usec, false);
 
-        t = strndupa(t, last_space - t);
-
         shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
         if (shared == MAP_FAILED)
                 return negative_errno();
 
-        pid = fork();
-
-        if (pid == -1) {
-                int fork_errno = errno;
+        r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
+        if (r < 0) {
                 (void) munmap(shared, sizeof *shared);
-                return -fork_errno;
+                return r;
         }
+        if (r == 0) {
+                bool with_tz = true;
 
-        if (pid == 0) {
-                if (setenv("TZ", timezone, 1) != 0) {
+                if (setenv("TZ", tz, 1) != 0) {
                         shared->return_value = negative_errno();
                         _exit(EXIT_FAILURE);
                 }
 
                 tzset();
 
-                shared->return_value = parse_timestamp_impl(t, &shared->usec, true);
+                /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
+                 * Otherwise just cut it off */
+                with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
 
-                _exit(EXIT_SUCCESS);
-        }
+                /*cut off the timezone if we dont need it*/
+                if (with_tz)
+                        t = strndupa(t, last_space - t);
 
-        r = wait_for_terminate(pid, NULL);
-        if (r < 0) {
-                (void) munmap(shared, sizeof *shared);
-                return r;
+                shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
+
+                _exit(EXIT_SUCCESS);
         }
 
         tmp = *shared;
@@ -1074,7 +1061,11 @@ int parse_sec(const char *t, usec_t *usec) {
 }
 
 int parse_sec_fix_0(const char *t, usec_t *usec) {
+        assert(t);
+        assert(usec);
+
         t += strspn(t, WHITESPACE);
+
         if (streq(t, "0")) {
                 *usec = USEC_INFINITY;
                 return 0;
@@ -1279,8 +1270,7 @@ int get_timezones(char ***ret) {
         } else if (errno != ENOENT)
                 return -errno;
 
-        *ret = zones;
-        zones = NULL;
+        *ret = TAKE_PTR(zones);
 
         return 0;
 }
@@ -1300,7 +1290,7 @@ bool timezone_is_valid(const char *name) {
                 if (!(*p >= '0' && *p <= '9') &&
                     !(*p >= 'a' && *p <= 'z') &&
                     !(*p >= 'A' && *p <= 'Z') &&
-                    !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
+                    !IN_SET(*p, '-', '_', '+', '/'))
                         return false;
 
                 if (*p == '/') {
@@ -1369,8 +1359,7 @@ bool clock_supported(clockid_t clock) {
                 if (!clock_boottime_supported())
                         return false;
 
-                /* fall through */
-
+                _fallthrough_;
         default:
                 /* For everything else, check properly */
                 return clock_gettime(clock, &ts) >= 0;
@@ -1444,3 +1433,9 @@ usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
                 /* x lies in the past */
                 return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
 }
+
+bool in_utc_timezone(void) {
+        tzset();
+
+        return timezone == 0 && daylight == 0;
+}