]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/timer.c
core: make manager_serialize() a bit easier to read by adding predicate function
[thirdparty/systemd.git] / src / core / timer.c
index 55197faa5932751570e3708fda89cd832a6ff41b..111aa428774855f20a71ffecc470ba6a4ed93faf 100644 (file)
@@ -1,22 +1,4 @@
 /* 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>
 
@@ -91,7 +73,7 @@ static int timer_verify(Timer *t) {
 
         if (!t->values) {
                 log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
-                return -EINVAL;
+                return -ENOEXEC;
         }
 
         return 0;
@@ -106,18 +88,18 @@ static int timer_add_default_dependencies(Timer *t) {
         if (!UNIT(t)->default_dependencies)
                 return 0;
 
-        r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+        r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
         if (r < 0)
                 return r;
 
         if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
-                r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+                r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
                 if (r < 0)
                         return r;
 
                 LIST_FOREACH(value, v, t->values) {
                         if (v->base == TIMER_CALENDAR) {
-                                r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+                                r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
                                 if (r < 0)
                                         return r;
                                 break;
@@ -125,7 +107,7 @@ static int timer_add_default_dependencies(Timer *t) {
                 }
         }
 
-        return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+        return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
 }
 
 static int timer_add_trigger_dependencies(Timer *t) {
@@ -277,7 +259,7 @@ static void timer_set_state(Timer *t, TimerState state) {
         if (state != old_state)
                 log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
 
-        unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
+        unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
 }
 
 static void timer_enter_waiting(Timer *t, bool initial);
@@ -354,7 +336,6 @@ static void timer_enter_waiting(Timer *t, bool initial) {
         bool found_monotonic = false, found_realtime = false;
         bool leave_around = false;
         triple_timestamp ts;
-        usec_t base = 0;
         TimerValue *v;
         Unit *trigger;
         int r;
@@ -372,7 +353,6 @@ static void timer_enter_waiting(Timer *t, bool initial) {
         t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
 
         LIST_FOREACH(value, v, t->values) {
-
                 if (v->disabled)
                         continue;
 
@@ -381,10 +361,17 @@ static void timer_enter_waiting(Timer *t, bool initial) {
 
                         /* If we know the last time this was
                          * triggered, schedule the job based relative
-                         * to that. If we don't just start from
-                         * now. */
+                         * to that. If we don't, just start from
+                         * the activation time. */
 
-                        b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts.realtime;
+                        if (t->last_trigger.realtime > 0)
+                                b = t->last_trigger.realtime;
+                        else {
+                                if (state_translation_table[t->state] == UNIT_ACTIVE)
+                                        b = UNIT(t)->inactive_exit_timestamp.realtime;
+                                else
+                                        b = ts.realtime;
+                        }
 
                         r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
                         if (r < 0)
@@ -397,7 +384,8 @@ static void timer_enter_waiting(Timer *t, bool initial) {
 
                         found_realtime = true;
 
-                } else  {
+                } else {
+                        usec_t base;
 
                         switch (v->base) {
 
@@ -417,7 +405,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
                                 /* In a container we don't want to include the time the host
                                  * was already up when the container started, so count from
                                  * our own startup. */
-                                /* fall through */
+                                _fallthrough_;
                         case TIMER_STARTUP:
                                 base = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
                                 break;
@@ -431,6 +419,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
 
                                 if (base <= 0)
                                         continue;
+                                base = MAX(base, t->last_trigger.monotonic);
 
                                 break;
 
@@ -443,6 +432,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
 
                                 if (base <= 0)
                                         continue;
+                                base = MAX(base, t->last_trigger.monotonic);
 
                                 break;
 
@@ -805,16 +795,37 @@ static void timer_reset_failed(Unit *u) {
 
 static void timer_time_change(Unit *u) {
         Timer *t = TIMER(u);
+        usec_t ts;
 
         assert(u);
 
         if (t->state != TIMER_WAITING)
                 return;
 
+        /* If we appear to have triggered in the future, the system clock must
+         * have been set backwards.  So let's rewind our own clock and allow
+         * the future trigger(s) to happen again :).  Exactly the same as when
+         * you start a timer unit with Persistent=yes. */
+        ts = now(CLOCK_REALTIME);
+        if (t->last_trigger.realtime > ts)
+                t->last_trigger.realtime = ts;
+
         log_unit_debug(u, "Time change, recalculating next elapse.");
         timer_enter_waiting(t, false);
 }
 
+static void timer_timezone_change(Unit *u) {
+        Timer *t = TIMER(u);
+
+        assert(u);
+
+        if (t->state != TIMER_WAITING)
+                return;
+
+        log_unit_debug(u, "Timezone change, recalculating next elapse.");
+        timer_enter_waiting(t, false);
+}
+
 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
         [TIMER_ACTIVE] = "OnActiveSec",
         [TIMER_BOOT] = "OnBootSec",
@@ -864,6 +875,7 @@ const UnitVTable timer_vtable = {
 
         .reset_failed = timer_reset_failed,
         .time_change = timer_time_change,
+        .timezone_change = timer_timezone_change,
 
         .bus_vtable = bus_timer_vtable,
         .bus_set_property = bus_timer_set_property,