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 : };
|