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