LCOV - code coverage report
Current view: top level - core - timer.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 3 362 0.8 %
Date: 2015-07-29 18:47:03 Functions: 6 30 20.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2010 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : 
      24             : #include "unit.h"
      25             : #include "unit-name.h"
      26             : #include "timer.h"
      27             : #include "dbus-timer.h"
      28             : #include "special.h"
      29             : #include "bus-util.h"
      30             : #include "bus-error.h"
      31             : 
      32             : static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
      33             :         [TIMER_DEAD] = UNIT_INACTIVE,
      34             :         [TIMER_WAITING] = UNIT_ACTIVE,
      35             :         [TIMER_RUNNING] = UNIT_ACTIVE,
      36             :         [TIMER_ELAPSED] = UNIT_ACTIVE,
      37             :         [TIMER_FAILED] = UNIT_FAILED
      38             : };
      39             : 
      40             : static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
      41             : 
      42           0 : static void timer_init(Unit *u) {
      43           0 :         Timer *t = TIMER(u);
      44             : 
      45           0 :         assert(u);
      46           0 :         assert(u->load_state == UNIT_STUB);
      47             : 
      48           0 :         t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
      49           0 :         t->next_elapse_realtime = USEC_INFINITY;
      50           0 :         t->accuracy_usec = u->manager->default_timer_accuracy_usec;
      51           0 : }
      52             : 
      53           0 : void timer_free_values(Timer *t) {
      54             :         TimerValue *v;
      55             : 
      56           0 :         assert(t);
      57             : 
      58           0 :         while ((v = t->values)) {
      59           0 :                 LIST_REMOVE(value, t->values, v);
      60             : 
      61           0 :                 if (v->calendar_spec)
      62           0 :                         calendar_spec_free(v->calendar_spec);
      63             : 
      64           0 :                 free(v);
      65             :         }
      66           0 : }
      67             : 
      68           0 : static void timer_done(Unit *u) {
      69           0 :         Timer *t = TIMER(u);
      70             : 
      71           0 :         assert(t);
      72             : 
      73           0 :         timer_free_values(t);
      74             : 
      75           0 :         t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
      76           0 :         t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
      77             : 
      78           0 :         free(t->stamp_path);
      79           0 : }
      80             : 
      81           0 : static int timer_verify(Timer *t) {
      82           0 :         assert(t);
      83             : 
      84           0 :         if (UNIT(t)->load_state != UNIT_LOADED)
      85           0 :                 return 0;
      86             : 
      87           0 :         if (!t->values) {
      88           0 :                 log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
      89           0 :                 return -EINVAL;
      90             :         }
      91             : 
      92           0 :         return 0;
      93             : }
      94             : 
      95           0 : static int timer_add_default_dependencies(Timer *t) {
      96             :         int r;
      97             :         TimerValue *v;
      98             : 
      99           0 :         assert(t);
     100             : 
     101           0 :         r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
     102           0 :         if (r < 0)
     103           0 :                 return r;
     104             : 
     105           0 :         if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
     106           0 :                 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
     107           0 :                 if (r < 0)
     108           0 :                         return r;
     109             : 
     110           0 :                 LIST_FOREACH(value, v, t->values) {
     111           0 :                         if (v->base == TIMER_CALENDAR) {
     112           0 :                                 r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true);
     113           0 :                                 if (r < 0)
     114           0 :                                         return r;
     115           0 :                                 break;
     116             :                         }
     117             :                 }
     118             :         }
     119             : 
     120           0 :         return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
     121             : }
     122             : 
     123           0 : static int timer_setup_persistent(Timer *t) {
     124             :         int r;
     125             : 
     126           0 :         assert(t);
     127             : 
     128           0 :         if (!t->persistent)
     129           0 :                 return 0;
     130             : 
     131           0 :         if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
     132             : 
     133           0 :                 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
     134           0 :                 if (r < 0)
     135           0 :                         return r;
     136             : 
     137           0 :                 t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
     138             :         } else {
     139             :                 const char *e;
     140             : 
     141           0 :                 e = getenv("XDG_DATA_HOME");
     142           0 :                 if (e)
     143           0 :                         t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id, NULL);
     144             :                 else {
     145             : 
     146           0 :                         _cleanup_free_ char *h = NULL;
     147             : 
     148           0 :                         r = get_home_dir(&h);
     149           0 :                         if (r < 0)
     150           0 :                                 return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m");
     151             : 
     152           0 :                         t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id, NULL);
     153             :                 }
     154             :         }
     155             : 
     156           0 :         if (!t->stamp_path)
     157           0 :                 return log_oom();
     158             : 
     159           0 :         return 0;
     160             : }
     161             : 
     162           0 : static int timer_load(Unit *u) {
     163           0 :         Timer *t = TIMER(u);
     164             :         int r;
     165             : 
     166           0 :         assert(u);
     167           0 :         assert(u->load_state == UNIT_STUB);
     168             : 
     169           0 :         r = unit_load_fragment_and_dropin(u);
     170           0 :         if (r < 0)
     171           0 :                 return r;
     172             : 
     173           0 :         if (u->load_state == UNIT_LOADED) {
     174             : 
     175           0 :                 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
     176             :                         Unit *x;
     177             : 
     178           0 :                         r = unit_load_related_unit(u, ".service", &x);
     179           0 :                         if (r < 0)
     180           0 :                                 return r;
     181             : 
     182           0 :                         r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
     183           0 :                         if (r < 0)
     184           0 :                                 return r;
     185             :                 }
     186             : 
     187           0 :                 r = timer_setup_persistent(t);
     188           0 :                 if (r < 0)
     189           0 :                         return r;
     190             : 
     191           0 :                 if (u->default_dependencies) {
     192           0 :                         r = timer_add_default_dependencies(t);
     193           0 :                         if (r < 0)
     194           0 :                                 return r;
     195             :                 }
     196             :         }
     197             : 
     198           0 :         return timer_verify(t);
     199             : }
     200             : 
     201           0 : static void timer_dump(Unit *u, FILE *f, const char *prefix) {
     202             :         char buf[FORMAT_TIMESPAN_MAX];
     203           0 :         Timer *t = TIMER(u);
     204             :         Unit *trigger;
     205             :         TimerValue *v;
     206             : 
     207           0 :         trigger = UNIT_TRIGGER(u);
     208             : 
     209           0 :         fprintf(f,
     210             :                 "%sTimer State: %s\n"
     211             :                 "%sResult: %s\n"
     212             :                 "%sUnit: %s\n"
     213             :                 "%sPersistent: %s\n"
     214             :                 "%sWakeSystem: %s\n"
     215             :                 "%sAccuracy: %s\n",
     216             :                 prefix, timer_state_to_string(t->state),
     217             :                 prefix, timer_result_to_string(t->result),
     218             :                 prefix, trigger ? trigger->id : "n/a",
     219           0 :                 prefix, yes_no(t->persistent),
     220           0 :                 prefix, yes_no(t->wake_system),
     221             :                 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
     222             : 
     223           0 :         LIST_FOREACH(value, v, t->values) {
     224             : 
     225           0 :                 if (v->base == TIMER_CALENDAR) {
     226           0 :                         _cleanup_free_ char *p = NULL;
     227             : 
     228           0 :                         calendar_spec_to_string(v->calendar_spec, &p);
     229             : 
     230           0 :                         fprintf(f,
     231             :                                 "%s%s: %s\n",
     232             :                                 prefix,
     233             :                                 timer_base_to_string(v->base),
     234             :                                 strna(p));
     235             :                 } else  {
     236             :                         char timespan1[FORMAT_TIMESPAN_MAX];
     237             : 
     238           0 :                         fprintf(f,
     239             :                                 "%s%s: %s\n",
     240             :                                 prefix,
     241             :                                 timer_base_to_string(v->base),
     242             :                                 format_timespan(timespan1, sizeof(timespan1), v->value, 0));
     243             :                 }
     244             :         }
     245           0 : }
     246             : 
     247           0 : static void timer_set_state(Timer *t, TimerState state) {
     248             :         TimerState old_state;
     249           0 :         assert(t);
     250             : 
     251           0 :         old_state = t->state;
     252           0 :         t->state = state;
     253             : 
     254           0 :         if (state != TIMER_WAITING) {
     255           0 :                 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
     256           0 :                 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
     257             :         }
     258             : 
     259           0 :         if (state != old_state)
     260           0 :                 log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
     261             : 
     262           0 :         unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
     263           0 : }
     264             : 
     265             : static void timer_enter_waiting(Timer *t, bool initial);
     266             : 
     267           0 : static int timer_coldplug(Unit *u) {
     268           0 :         Timer *t = TIMER(u);
     269             : 
     270           0 :         assert(t);
     271           0 :         assert(t->state == TIMER_DEAD);
     272             : 
     273           0 :         if (t->deserialized_state != t->state) {
     274             : 
     275           0 :                 if (t->deserialized_state == TIMER_WAITING)
     276           0 :                         timer_enter_waiting(t, false);
     277             :                 else
     278           0 :                         timer_set_state(t, t->deserialized_state);
     279             :         }
     280             : 
     281           0 :         return 0;
     282             : }
     283             : 
     284           0 : static void timer_enter_dead(Timer *t, TimerResult f) {
     285           0 :         assert(t);
     286             : 
     287           0 :         if (f != TIMER_SUCCESS)
     288           0 :                 t->result = f;
     289             : 
     290           0 :         timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
     291           0 : }
     292             : 
     293           0 : static usec_t monotonic_to_boottime(usec_t t) {
     294             :         usec_t a, b;
     295             : 
     296           0 :         if (t <= 0)
     297           0 :                 return 0;
     298             : 
     299           0 :         a = now(CLOCK_BOOTTIME);
     300           0 :         b = now(CLOCK_MONOTONIC);
     301             : 
     302           0 :         if (t + a > b)
     303           0 :                 return t + a - b;
     304             :         else
     305           0 :                 return 0;
     306             : }
     307             : 
     308           0 : static void timer_enter_waiting(Timer *t, bool initial) {
     309           0 :         bool found_monotonic = false, found_realtime = false;
     310             :         usec_t ts_realtime, ts_monotonic;
     311           0 :         usec_t base = 0;
     312             :         TimerValue *v;
     313             :         int r;
     314             : 
     315             :         /* If we shall wake the system we use the boottime clock
     316             :          * rather than the monotonic clock. */
     317             : 
     318           0 :         ts_realtime = now(CLOCK_REALTIME);
     319           0 :         ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
     320           0 :         t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
     321             : 
     322           0 :         LIST_FOREACH(value, v, t->values) {
     323             : 
     324           0 :                 if (v->disabled)
     325           0 :                         continue;
     326             : 
     327           0 :                 if (v->base == TIMER_CALENDAR) {
     328             :                         usec_t b;
     329             : 
     330             :                         /* If we know the last time this was
     331             :                          * triggered, schedule the job based relative
     332             :                          * to that. If we don't just start from
     333             :                          * now. */
     334             : 
     335           0 :                         b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts_realtime;
     336             : 
     337           0 :                         r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
     338           0 :                         if (r < 0)
     339           0 :                                 continue;
     340             : 
     341           0 :                         if (!found_realtime)
     342           0 :                                 t->next_elapse_realtime = v->next_elapse;
     343             :                         else
     344           0 :                                 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
     345             : 
     346           0 :                         found_realtime = true;
     347             : 
     348             :                 } else  {
     349           0 :                         switch (v->base) {
     350             : 
     351             :                         case TIMER_ACTIVE:
     352           0 :                                 if (state_translation_table[t->state] == UNIT_ACTIVE)
     353           0 :                                         base = UNIT(t)->inactive_exit_timestamp.monotonic;
     354             :                                 else
     355           0 :                                         base = ts_monotonic;
     356           0 :                                 break;
     357             : 
     358             :                         case TIMER_BOOT:
     359             :                                 /* CLOCK_MONOTONIC equals the uptime on Linux */
     360           0 :                                 base = 0;
     361           0 :                                 break;
     362             : 
     363             :                         case TIMER_STARTUP:
     364           0 :                                 base = UNIT(t)->manager->userspace_timestamp.monotonic;
     365           0 :                                 break;
     366             : 
     367             :                         case TIMER_UNIT_ACTIVE:
     368             : 
     369           0 :                                 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
     370             : 
     371           0 :                                 if (base <= 0)
     372           0 :                                         base = t->last_trigger.monotonic;
     373             : 
     374           0 :                                 if (base <= 0)
     375           0 :                                         continue;
     376             : 
     377           0 :                                 break;
     378             : 
     379             :                         case TIMER_UNIT_INACTIVE:
     380             : 
     381           0 :                                 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
     382             : 
     383           0 :                                 if (base <= 0)
     384           0 :                                         base = t->last_trigger.monotonic;
     385             : 
     386           0 :                                 if (base <= 0)
     387           0 :                                         continue;
     388             : 
     389           0 :                                 break;
     390             : 
     391             :                         default:
     392           0 :                                 assert_not_reached("Unknown timer base");
     393             :                         }
     394             : 
     395           0 :                         if (t->wake_system)
     396           0 :                                 base = monotonic_to_boottime(base);
     397             : 
     398           0 :                         v->next_elapse = base + v->value;
     399             : 
     400           0 :                         if (!initial && v->next_elapse < ts_monotonic && IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
     401             :                                 /* This is a one time trigger, disable it now */
     402           0 :                                 v->disabled = true;
     403           0 :                                 continue;
     404             :                         }
     405             : 
     406           0 :                         if (!found_monotonic)
     407           0 :                                 t->next_elapse_monotonic_or_boottime = v->next_elapse;
     408             :                         else
     409           0 :                                 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
     410             : 
     411           0 :                         found_monotonic = true;
     412             :                 }
     413             :         }
     414             : 
     415           0 :         if (!found_monotonic && !found_realtime) {
     416           0 :                 log_unit_debug(UNIT(t), "Timer is elapsed.");
     417           0 :                 timer_set_state(t, TIMER_ELAPSED);
     418           0 :                 return;
     419             :         }
     420             : 
     421           0 :         if (found_monotonic) {
     422             :                 char buf[FORMAT_TIMESPAN_MAX];
     423             : 
     424           0 :                 log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
     425             : 
     426           0 :                 if (t->monotonic_event_source) {
     427           0 :                         r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
     428           0 :                         if (r < 0)
     429           0 :                                 goto fail;
     430             : 
     431           0 :                         r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
     432           0 :                         if (r < 0)
     433           0 :                                 goto fail;
     434             :                 } else {
     435             : 
     436           0 :                         r = sd_event_add_time(
     437           0 :                                         UNIT(t)->manager->event,
     438             :                                         &t->monotonic_event_source,
     439           0 :                                         t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
     440             :                                         t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
     441             :                                         timer_dispatch, t);
     442           0 :                         if (r < 0)
     443           0 :                                 goto fail;
     444             : 
     445           0 :                         (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
     446             :                 }
     447             : 
     448           0 :         } else if (t->monotonic_event_source) {
     449             : 
     450           0 :                 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
     451           0 :                 if (r < 0)
     452           0 :                         goto fail;
     453             :         }
     454             : 
     455           0 :         if (found_realtime) {
     456             :                 char buf[FORMAT_TIMESTAMP_MAX];
     457           0 :                 log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
     458             : 
     459           0 :                 if (t->realtime_event_source) {
     460           0 :                         r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
     461           0 :                         if (r < 0)
     462           0 :                                 goto fail;
     463             : 
     464           0 :                         r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
     465           0 :                         if (r < 0)
     466           0 :                                 goto fail;
     467             :                 } else {
     468           0 :                         r = sd_event_add_time(
     469           0 :                                         UNIT(t)->manager->event,
     470             :                                         &t->realtime_event_source,
     471           0 :                                         t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
     472             :                                         t->next_elapse_realtime, t->accuracy_usec,
     473             :                                         timer_dispatch, t);
     474           0 :                         if (r < 0)
     475           0 :                                 goto fail;
     476             : 
     477           0 :                         (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
     478             :                 }
     479             : 
     480           0 :         } else if (t->realtime_event_source) {
     481             : 
     482           0 :                 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
     483           0 :                 if (r < 0)
     484           0 :                         goto fail;
     485             :         }
     486             : 
     487           0 :         timer_set_state(t, TIMER_WAITING);
     488           0 :         return;
     489             : 
     490             : fail:
     491           0 :         log_unit_warning_errno(UNIT(t), r, "Failed to enter waiting state: %m");
     492           0 :         timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
     493             : }
     494             : 
     495           0 : static void timer_enter_running(Timer *t) {
     496           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     497             :         int r;
     498             : 
     499           0 :         assert(t);
     500             : 
     501             :         /* Don't start job if we are supposed to go down */
     502           0 :         if (unit_stop_pending(UNIT(t)))
     503           0 :                 return;
     504             : 
     505           0 :         r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
     506             :                             JOB_REPLACE, true, &error, NULL);
     507           0 :         if (r < 0)
     508           0 :                 goto fail;
     509             : 
     510           0 :         dual_timestamp_get(&t->last_trigger);
     511             : 
     512           0 :         if (t->stamp_path)
     513           0 :                 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0);
     514             : 
     515           0 :         timer_set_state(t, TIMER_RUNNING);
     516           0 :         return;
     517             : 
     518             : fail:
     519           0 :         log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
     520           0 :         timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
     521             : }
     522             : 
     523           0 : static int timer_start(Unit *u) {
     524           0 :         Timer *t = TIMER(u);
     525             :         TimerValue *v;
     526             : 
     527           0 :         assert(t);
     528           0 :         assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
     529             : 
     530           0 :         if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
     531           0 :                 return -ENOENT;
     532             : 
     533           0 :         t->last_trigger = DUAL_TIMESTAMP_NULL;
     534             : 
     535             :         /* Reenable all timers that depend on unit activation time */
     536           0 :         LIST_FOREACH(value, v, t->values)
     537           0 :                 if (v->base == TIMER_ACTIVE)
     538           0 :                         v->disabled = false;
     539             : 
     540           0 :         if (t->stamp_path) {
     541             :                 struct stat st;
     542             : 
     543           0 :                 if (stat(t->stamp_path, &st) >= 0)
     544           0 :                         t->last_trigger.realtime = timespec_load(&st.st_atim);
     545           0 :                 else if (errno == ENOENT)
     546             :                         /* The timer has never run before,
     547             :                          * make sure a stamp file exists.
     548             :                          */
     549           0 :                         touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
     550             :         }
     551             : 
     552           0 :         t->result = TIMER_SUCCESS;
     553           0 :         timer_enter_waiting(t, true);
     554           0 :         return 1;
     555             : }
     556             : 
     557           0 : static int timer_stop(Unit *u) {
     558           0 :         Timer *t = TIMER(u);
     559             : 
     560           0 :         assert(t);
     561           0 :         assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
     562             : 
     563           0 :         timer_enter_dead(t, TIMER_SUCCESS);
     564           0 :         return 1;
     565             : }
     566             : 
     567           0 : static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
     568           0 :         Timer *t = TIMER(u);
     569             : 
     570           0 :         assert(u);
     571           0 :         assert(f);
     572           0 :         assert(fds);
     573             : 
     574           0 :         unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
     575           0 :         unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
     576             : 
     577           0 :         if (t->last_trigger.realtime > 0)
     578           0 :                 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
     579             : 
     580           0 :         if (t->last_trigger.monotonic > 0)
     581           0 :                 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
     582             : 
     583           0 :         return 0;
     584             : }
     585             : 
     586           0 : static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
     587           0 :         Timer *t = TIMER(u);
     588             :         int r;
     589             : 
     590           0 :         assert(u);
     591           0 :         assert(key);
     592           0 :         assert(value);
     593           0 :         assert(fds);
     594             : 
     595           0 :         if (streq(key, "state")) {
     596             :                 TimerState state;
     597             : 
     598           0 :                 state = timer_state_from_string(value);
     599           0 :                 if (state < 0)
     600           0 :                         log_unit_debug(u, "Failed to parse state value: %s", value);
     601             :                 else
     602           0 :                         t->deserialized_state = state;
     603           0 :         } else if (streq(key, "result")) {
     604             :                 TimerResult f;
     605             : 
     606           0 :                 f = timer_result_from_string(value);
     607           0 :                 if (f < 0)
     608           0 :                         log_unit_debug(u, "Failed to parse result value: %s", value);
     609           0 :                 else if (f != TIMER_SUCCESS)
     610           0 :                         t->result = f;
     611           0 :         } else if (streq(key, "last-trigger-realtime")) {
     612             : 
     613           0 :                 r = safe_atou64(value, &t->last_trigger.realtime);
     614           0 :                 if (r < 0)
     615           0 :                         log_unit_debug(u, "Failed to parse last-trigger-realtime value: %s", value);
     616             : 
     617           0 :         } else if (streq(key, "last-trigger-monotonic")) {
     618             : 
     619           0 :                 r = safe_atou64(value, &t->last_trigger.monotonic);
     620           0 :                 if (r < 0)
     621           0 :                         log_unit_debug(u, "Failed to parse last-trigger-monotonic value: %s", value);
     622             : 
     623             :         } else
     624           0 :                 log_unit_debug(u, "Unknown serialization key: %s", key);
     625             : 
     626           0 :         return 0;
     627             : }
     628             : 
     629           0 : _pure_ static UnitActiveState timer_active_state(Unit *u) {
     630           0 :         assert(u);
     631             : 
     632           0 :         return state_translation_table[TIMER(u)->state];
     633             : }
     634             : 
     635           0 : _pure_ static const char *timer_sub_state_to_string(Unit *u) {
     636           0 :         assert(u);
     637             : 
     638           0 :         return timer_state_to_string(TIMER(u)->state);
     639             : }
     640             : 
     641           0 : static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
     642           0 :         Timer *t = TIMER(userdata);
     643             : 
     644           0 :         assert(t);
     645             : 
     646           0 :         if (t->state != TIMER_WAITING)
     647           0 :                 return 0;
     648             : 
     649           0 :         log_unit_debug(UNIT(t), "Timer elapsed.");
     650           0 :         timer_enter_running(t);
     651           0 :         return 0;
     652             : }
     653             : 
     654           0 : static void timer_trigger_notify(Unit *u, Unit *other) {
     655           0 :         Timer *t = TIMER(u);
     656             :         TimerValue *v;
     657             : 
     658           0 :         assert(u);
     659           0 :         assert(other);
     660             : 
     661           0 :         if (other->load_state != UNIT_LOADED)
     662           0 :                 return;
     663             : 
     664             :         /* Reenable all timers that depend on unit state */
     665           0 :         LIST_FOREACH(value, v, t->values)
     666           0 :                 if (v->base == TIMER_UNIT_ACTIVE ||
     667           0 :                     v->base == TIMER_UNIT_INACTIVE)
     668           0 :                         v->disabled = false;
     669             : 
     670           0 :         switch (t->state) {
     671             : 
     672             :         case TIMER_WAITING:
     673             :         case TIMER_ELAPSED:
     674             : 
     675             :                 /* Recalculate sleep time */
     676           0 :                 timer_enter_waiting(t, false);
     677           0 :                 break;
     678             : 
     679             :         case TIMER_RUNNING:
     680             : 
     681           0 :                 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
     682           0 :                         log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
     683           0 :                         timer_enter_waiting(t, false);
     684             :                 }
     685           0 :                 break;
     686             : 
     687             :         case TIMER_DEAD:
     688             :         case TIMER_FAILED:
     689           0 :                 break;
     690             : 
     691             :         default:
     692           0 :                 assert_not_reached("Unknown timer state");
     693             :         }
     694             : }
     695             : 
     696           0 : static void timer_reset_failed(Unit *u) {
     697           0 :         Timer *t = TIMER(u);
     698             : 
     699           0 :         assert(t);
     700             : 
     701           0 :         if (t->state == TIMER_FAILED)
     702           0 :                 timer_set_state(t, TIMER_DEAD);
     703             : 
     704           0 :         t->result = TIMER_SUCCESS;
     705           0 : }
     706             : 
     707           0 : static void timer_time_change(Unit *u) {
     708           0 :         Timer *t = TIMER(u);
     709             : 
     710           0 :         assert(u);
     711             : 
     712           0 :         if (t->state != TIMER_WAITING)
     713           0 :                 return;
     714             : 
     715           0 :         log_unit_debug(u, "Time change, recalculating next elapse.");
     716           0 :         timer_enter_waiting(t, false);
     717             : }
     718             : 
     719             : static const char* const timer_state_table[_TIMER_STATE_MAX] = {
     720             :         [TIMER_DEAD] = "dead",
     721             :         [TIMER_WAITING] = "waiting",
     722             :         [TIMER_RUNNING] = "running",
     723             :         [TIMER_ELAPSED] = "elapsed",
     724             :         [TIMER_FAILED] = "failed"
     725             : };
     726             : 
     727          14 : DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
     728             : 
     729             : static const char* const timer_base_table[_TIMER_BASE_MAX] = {
     730             :         [TIMER_ACTIVE] = "OnActiveSec",
     731             :         [TIMER_BOOT] = "OnBootSec",
     732             :         [TIMER_STARTUP] = "OnStartupSec",
     733             :         [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
     734             :         [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
     735             :         [TIMER_CALENDAR] = "OnCalendar"
     736             : };
     737             : 
     738          16 : DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
     739             : 
     740             : static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
     741             :         [TIMER_SUCCESS] = "success",
     742             :         [TIMER_FAILURE_RESOURCES] = "resources"
     743             : };
     744             : 
     745           8 : DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
     746             : 
     747             : const UnitVTable timer_vtable = {
     748             :         .object_size = sizeof(Timer),
     749             : 
     750             :         .sections =
     751             :                 "Unit\0"
     752             :                 "Timer\0"
     753             :                 "Install\0",
     754             :         .private_section = "Timer",
     755             : 
     756             :         .init = timer_init,
     757             :         .done = timer_done,
     758             :         .load = timer_load,
     759             : 
     760             :         .coldplug = timer_coldplug,
     761             : 
     762             :         .dump = timer_dump,
     763             : 
     764             :         .start = timer_start,
     765             :         .stop = timer_stop,
     766             : 
     767             :         .serialize = timer_serialize,
     768             :         .deserialize_item = timer_deserialize_item,
     769             : 
     770             :         .active_state = timer_active_state,
     771             :         .sub_state_to_string = timer_sub_state_to_string,
     772             : 
     773             :         .trigger_notify = timer_trigger_notify,
     774             : 
     775             :         .reset_failed = timer_reset_failed,
     776             :         .time_change = timer_time_change,
     777             : 
     778             :         .bus_interface = "org.freedesktop.systemd1.Timer",
     779             :         .bus_vtable = bus_timer_vtable,
     780             :         .bus_set_property = bus_timer_set_property,
     781             : 
     782             :         .can_transient = true,
     783             : };

Generated by: LCOV version 1.11