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