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