Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <sys/stat.h>
4 : : #include <sys/types.h>
5 : : #include <unistd.h>
6 : :
7 : : #include <errno.h>
8 : :
9 : : #include "alloc-util.h"
10 : : #include "bus-error.h"
11 : : #include "bus-util.h"
12 : : #include "dbus-timer.h"
13 : : #include "dbus-unit.h"
14 : : #include "fs-util.h"
15 : : #include "parse-util.h"
16 : : #include "random-util.h"
17 : : #include "serialize.h"
18 : : #include "special.h"
19 : : #include "string-table.h"
20 : : #include "string-util.h"
21 : : #include "timer.h"
22 : : #include "unit-name.h"
23 : : #include "unit.h"
24 : : #include "user-util.h"
25 : : #include "virt.h"
26 : :
27 : : static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
28 : : [TIMER_DEAD] = UNIT_INACTIVE,
29 : : [TIMER_WAITING] = UNIT_ACTIVE,
30 : : [TIMER_RUNNING] = UNIT_ACTIVE,
31 : : [TIMER_ELAPSED] = UNIT_ACTIVE,
32 : : [TIMER_FAILED] = UNIT_FAILED
33 : : };
34 : :
35 : : static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
36 : :
37 : 0 : static void timer_init(Unit *u) {
38 : 0 : Timer *t = TIMER(u);
39 : :
40 [ # # ]: 0 : assert(u);
41 [ # # ]: 0 : assert(u->load_state == UNIT_STUB);
42 : :
43 : 0 : t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
44 : 0 : t->next_elapse_realtime = USEC_INFINITY;
45 : 0 : t->accuracy_usec = u->manager->default_timer_accuracy_usec;
46 : 0 : t->remain_after_elapse = true;
47 : 0 : }
48 : :
49 : 0 : void timer_free_values(Timer *t) {
50 : : TimerValue *v;
51 : :
52 [ # # ]: 0 : assert(t);
53 : :
54 [ # # ]: 0 : while ((v = t->values)) {
55 [ # # # # : 0 : LIST_REMOVE(value, t->values, v);
# # # # ]
56 : 0 : calendar_spec_free(v->calendar_spec);
57 : 0 : free(v);
58 : : }
59 : 0 : }
60 : :
61 : 0 : static void timer_done(Unit *u) {
62 : 0 : Timer *t = TIMER(u);
63 : :
64 [ # # ]: 0 : assert(t);
65 : :
66 : 0 : timer_free_values(t);
67 : :
68 : 0 : t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
69 : 0 : t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
70 : :
71 : 0 : free(t->stamp_path);
72 : 0 : }
73 : :
74 : 0 : static int timer_verify(Timer *t) {
75 [ # # ]: 0 : assert(t);
76 : :
77 [ # # # # ]: 0 : if (UNIT(t)->load_state != UNIT_LOADED)
78 : 0 : return 0;
79 : :
80 [ # # # # : 0 : if (!t->values && !t->on_clock_change && !t->on_timezone_change) {
# # ]
81 [ # # # # ]: 0 : log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
82 : 0 : return -ENOEXEC;
83 : : }
84 : :
85 : 0 : return 0;
86 : : }
87 : :
88 : 0 : static int timer_add_default_dependencies(Timer *t) {
89 : : int r;
90 : : TimerValue *v;
91 : :
92 [ # # ]: 0 : assert(t);
93 : :
94 [ # # # # ]: 0 : if (!UNIT(t)->default_dependencies)
95 : 0 : return 0;
96 : :
97 [ # # ]: 0 : r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
98 [ # # ]: 0 : if (r < 0)
99 : 0 : return r;
100 : :
101 [ # # # # ]: 0 : if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
102 [ # # ]: 0 : r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
103 [ # # ]: 0 : if (r < 0)
104 : 0 : return r;
105 : :
106 [ # # ]: 0 : LIST_FOREACH(value, v, t->values) {
107 [ # # ]: 0 : if (v->base == TIMER_CALENDAR) {
108 [ # # ]: 0 : r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
109 [ # # ]: 0 : if (r < 0)
110 : 0 : return r;
111 : 0 : break;
112 : : }
113 : : }
114 : : }
115 : :
116 [ # # ]: 0 : return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
117 : : }
118 : :
119 : 0 : static int timer_add_trigger_dependencies(Timer *t) {
120 : : Unit *x;
121 : : int r;
122 : :
123 [ # # ]: 0 : assert(t);
124 : :
125 [ # # # # ]: 0 : if (!hashmap_isempty(UNIT(t)->dependencies[UNIT_TRIGGERS]))
126 : 0 : return 0;
127 : :
128 [ # # ]: 0 : r = unit_load_related_unit(UNIT(t), ".service", &x);
129 [ # # ]: 0 : if (r < 0)
130 : 0 : return r;
131 : :
132 [ # # ]: 0 : return unit_add_two_dependencies(UNIT(t), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
133 : : }
134 : :
135 : 0 : static int timer_setup_persistent(Timer *t) {
136 : : int r;
137 : :
138 [ # # ]: 0 : assert(t);
139 : :
140 [ # # ]: 0 : if (!t->persistent)
141 : 0 : return 0;
142 : :
143 [ # # # # ]: 0 : if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
144 : :
145 [ # # ]: 0 : r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE);
146 [ # # ]: 0 : if (r < 0)
147 : 0 : return r;
148 : :
149 [ # # ]: 0 : t->stamp_path = strjoin("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
150 : : } else {
151 : : const char *e;
152 : :
153 : 0 : e = getenv("XDG_DATA_HOME");
154 [ # # ]: 0 : if (e)
155 [ # # ]: 0 : t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id);
156 : : else {
157 : :
158 [ # # ]: 0 : _cleanup_free_ char *h = NULL;
159 : :
160 : 0 : r = get_home_dir(&h);
161 [ # # ]: 0 : if (r < 0)
162 [ # # # # ]: 0 : return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m");
163 : :
164 [ # # ]: 0 : t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id);
165 : : }
166 : : }
167 : :
168 [ # # ]: 0 : if (!t->stamp_path)
169 : 0 : return log_oom();
170 : :
171 : 0 : return 0;
172 : : }
173 : :
174 : 0 : static int timer_load(Unit *u) {
175 : 0 : Timer *t = TIMER(u);
176 : : int r;
177 : :
178 [ # # ]: 0 : assert(u);
179 [ # # ]: 0 : assert(u->load_state == UNIT_STUB);
180 : :
181 : 0 : r = unit_load_fragment_and_dropin(u);
182 [ # # ]: 0 : if (r < 0)
183 : 0 : return r;
184 : :
185 [ # # ]: 0 : if (u->load_state == UNIT_LOADED) {
186 : :
187 : 0 : r = timer_add_trigger_dependencies(t);
188 [ # # ]: 0 : if (r < 0)
189 : 0 : return r;
190 : :
191 : 0 : r = timer_setup_persistent(t);
192 [ # # ]: 0 : if (r < 0)
193 : 0 : return r;
194 : :
195 : 0 : r = timer_add_default_dependencies(t);
196 [ # # ]: 0 : if (r < 0)
197 : 0 : return r;
198 : : }
199 : :
200 : 0 : return timer_verify(t);
201 : : }
202 : :
203 : 0 : static void timer_dump(Unit *u, FILE *f, const char *prefix) {
204 : : char buf[FORMAT_TIMESPAN_MAX];
205 : 0 : Timer *t = TIMER(u);
206 : : Unit *trigger;
207 : : TimerValue *v;
208 : :
209 : 0 : trigger = UNIT_TRIGGER(u);
210 : :
211 [ # # ]: 0 : fprintf(f,
212 : : "%sTimer State: %s\n"
213 : : "%sResult: %s\n"
214 : : "%sUnit: %s\n"
215 : : "%sPersistent: %s\n"
216 : : "%sWakeSystem: %s\n"
217 : : "%sAccuracy: %s\n"
218 : : "%sRemainAfterElapse: %s\n"
219 : : "%sOnClockChange: %s\n"
220 : : "%sOnTimeZoneChange %s\n",
221 : : prefix, timer_state_to_string(t->state),
222 : : prefix, timer_result_to_string(t->result),
223 : : prefix, trigger ? trigger->id : "n/a",
224 : 0 : prefix, yes_no(t->persistent),
225 : 0 : prefix, yes_no(t->wake_system),
226 : : prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
227 : 0 : prefix, yes_no(t->remain_after_elapse),
228 : 0 : prefix, yes_no(t->on_clock_change),
229 : 0 : prefix, yes_no(t->on_timezone_change));
230 : :
231 [ # # ]: 0 : LIST_FOREACH(value, v, t->values) {
232 : :
233 [ # # ]: 0 : if (v->base == TIMER_CALENDAR) {
234 : 0 : _cleanup_free_ char *p = NULL;
235 : :
236 : 0 : (void) calendar_spec_to_string(v->calendar_spec, &p);
237 : :
238 : 0 : fprintf(f,
239 : : "%s%s: %s\n",
240 : : prefix,
241 : : timer_base_to_string(v->base),
242 : : strna(p));
243 : : } else {
244 : : char timespan1[FORMAT_TIMESPAN_MAX];
245 : :
246 : 0 : fprintf(f,
247 : : "%s%s: %s\n",
248 : : prefix,
249 : : timer_base_to_string(v->base),
250 : : format_timespan(timespan1, sizeof(timespan1), v->value, 0));
251 : : }
252 : : }
253 : 0 : }
254 : :
255 : 0 : static void timer_set_state(Timer *t, TimerState state) {
256 : : TimerState old_state;
257 [ # # ]: 0 : assert(t);
258 : :
259 [ # # ]: 0 : if (t->state != state)
260 [ # # ]: 0 : bus_unit_send_pending_change_signal(UNIT(t), false);
261 : :
262 : 0 : old_state = t->state;
263 : 0 : t->state = state;
264 : :
265 [ # # ]: 0 : if (state != TIMER_WAITING) {
266 : 0 : t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
267 : 0 : t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
268 : 0 : t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
269 : 0 : t->next_elapse_realtime = USEC_INFINITY;
270 : : }
271 : :
272 [ # # ]: 0 : if (state != old_state)
273 [ # # # # ]: 0 : log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
274 : :
275 [ # # ]: 0 : unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
276 : 0 : }
277 : :
278 : : static void timer_enter_waiting(Timer *t, bool time_change);
279 : :
280 : 0 : static int timer_coldplug(Unit *u) {
281 : 0 : Timer *t = TIMER(u);
282 : :
283 [ # # ]: 0 : assert(t);
284 [ # # ]: 0 : assert(t->state == TIMER_DEAD);
285 : :
286 [ # # ]: 0 : if (t->deserialized_state == t->state)
287 : 0 : return 0;
288 : :
289 [ # # ]: 0 : if (t->deserialized_state == TIMER_WAITING)
290 : 0 : timer_enter_waiting(t, false);
291 : : else
292 : 0 : timer_set_state(t, t->deserialized_state);
293 : :
294 : 0 : return 0;
295 : : }
296 : :
297 : 0 : static void timer_enter_dead(Timer *t, TimerResult f) {
298 [ # # ]: 0 : assert(t);
299 : :
300 [ # # ]: 0 : if (t->result == TIMER_SUCCESS)
301 : 0 : t->result = f;
302 : :
303 [ # # ]: 0 : unit_log_result(UNIT(t), t->result == TIMER_SUCCESS, timer_result_to_string(t->result));
304 [ # # ]: 0 : timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
305 : 0 : }
306 : :
307 : 0 : static void timer_enter_elapsed(Timer *t, bool leave_around) {
308 [ # # ]: 0 : assert(t);
309 : :
310 : : /* If a unit is marked with RemainAfterElapse=yes we leave it
311 : : * around even after it elapsed once, so that starting it
312 : : * later again does not necessarily mean immediate
313 : : * retriggering. We unconditionally leave units with
314 : : * TIMER_UNIT_ACTIVE or TIMER_UNIT_INACTIVE triggers around,
315 : : * since they might be restarted automatically at any time
316 : : * later on. */
317 : :
318 [ # # # # ]: 0 : if (t->remain_after_elapse || leave_around)
319 : 0 : timer_set_state(t, TIMER_ELAPSED);
320 : : else
321 : 0 : timer_enter_dead(t, TIMER_SUCCESS);
322 : 0 : }
323 : :
324 : 0 : static void add_random(Timer *t, usec_t *v) {
325 : : char s[FORMAT_TIMESPAN_MAX];
326 : : usec_t add;
327 : :
328 [ # # ]: 0 : assert(t);
329 [ # # ]: 0 : assert(v);
330 : :
331 [ # # ]: 0 : if (t->random_usec == 0)
332 : 0 : return;
333 [ # # ]: 0 : if (*v == USEC_INFINITY)
334 : 0 : return;
335 : :
336 : 0 : add = random_u64() % t->random_usec;
337 : :
338 [ # # ]: 0 : if (*v + add < *v) /* overflow */
339 : 0 : *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
340 : : else
341 : 0 : *v += add;
342 : :
343 [ # # # # ]: 0 : log_unit_debug(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
344 : : }
345 : :
346 : 0 : static void timer_enter_waiting(Timer *t, bool time_change) {
347 : 0 : bool found_monotonic = false, found_realtime = false;
348 : 0 : bool leave_around = false;
349 : : triple_timestamp ts;
350 : : TimerValue *v;
351 : : Unit *trigger;
352 : : int r;
353 : :
354 [ # # ]: 0 : assert(t);
355 : :
356 [ # # ]: 0 : trigger = UNIT_TRIGGER(UNIT(t));
357 [ # # ]: 0 : if (!trigger) {
358 [ # # # # ]: 0 : log_unit_error(UNIT(t), "Unit to trigger vanished.");
359 : 0 : timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
360 : 0 : return;
361 : : }
362 : :
363 : 0 : triple_timestamp_get(&ts);
364 : 0 : t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
365 : :
366 [ # # ]: 0 : LIST_FOREACH(value, v, t->values) {
367 [ # # ]: 0 : if (v->disabled)
368 : 0 : continue;
369 : :
370 [ # # ]: 0 : if (v->base == TIMER_CALENDAR) {
371 : : usec_t b;
372 : :
373 : : /* If we know the last time this was
374 : : * triggered, schedule the job based relative
375 : : * to that. If we don't, just start from
376 : : * the activation time. */
377 : :
378 [ # # ]: 0 : if (t->last_trigger.realtime > 0)
379 : 0 : b = t->last_trigger.realtime;
380 : : else {
381 [ # # ]: 0 : if (state_translation_table[t->state] == UNIT_ACTIVE)
382 [ # # ]: 0 : b = UNIT(t)->inactive_exit_timestamp.realtime;
383 : : else
384 : 0 : b = ts.realtime;
385 : : }
386 : :
387 : 0 : r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
388 [ # # ]: 0 : if (r < 0)
389 : 0 : continue;
390 : :
391 : : /* To make the delay due to RandomizedDelaySec= work even at boot,
392 : : * if the scheduled time has already passed, set the time when systemd
393 : : * first started as the scheduled time.
394 : : * Also, we don't have to check t->persistent since the logic implicitly express true. */
395 [ # # # # ]: 0 : if (v->next_elapse < UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].realtime)
396 [ # # ]: 0 : v->next_elapse = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].realtime;
397 : :
398 [ # # ]: 0 : if (!found_realtime)
399 : 0 : t->next_elapse_realtime = v->next_elapse;
400 : : else
401 : 0 : t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
402 : :
403 : 0 : found_realtime = true;
404 : :
405 : : } else {
406 : : usec_t base;
407 : :
408 [ # # # # : 0 : switch (v->base) {
# # ]
409 : :
410 : 0 : case TIMER_ACTIVE:
411 [ # # ]: 0 : if (state_translation_table[t->state] == UNIT_ACTIVE)
412 [ # # ]: 0 : base = UNIT(t)->inactive_exit_timestamp.monotonic;
413 : : else
414 : 0 : base = ts.monotonic;
415 : 0 : break;
416 : :
417 : 0 : case TIMER_BOOT:
418 [ # # ]: 0 : if (detect_container() <= 0) {
419 : : /* CLOCK_MONOTONIC equals the uptime on Linux */
420 : 0 : base = 0;
421 : 0 : break;
422 : : }
423 : : /* In a container we don't want to include the time the host
424 : : * was already up when the container started, so count from
425 : : * our own startup. */
426 : : _fallthrough_;
427 : : case TIMER_STARTUP:
428 [ # # ]: 0 : base = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
429 : 0 : break;
430 : :
431 : 0 : case TIMER_UNIT_ACTIVE:
432 : 0 : leave_around = true;
433 : 0 : base = MAX(trigger->inactive_exit_timestamp.monotonic, t->last_trigger.monotonic);
434 [ # # ]: 0 : if (base <= 0)
435 : 0 : continue;
436 : 0 : break;
437 : :
438 : 0 : case TIMER_UNIT_INACTIVE:
439 : 0 : leave_around = true;
440 : 0 : base = MAX(trigger->inactive_enter_timestamp.monotonic, t->last_trigger.monotonic);
441 [ # # ]: 0 : if (base <= 0)
442 : 0 : continue;
443 : 0 : break;
444 : :
445 : 0 : default:
446 : 0 : assert_not_reached("Unknown timer base");
447 : : }
448 : :
449 [ # # # # ]: 0 : v->next_elapse = usec_add(usec_shift_clock(base, CLOCK_MONOTONIC, TIMER_MONOTONIC_CLOCK(t)), v->value);
450 : :
451 [ # # ]: 0 : if (dual_timestamp_is_set(&t->last_trigger) &&
452 [ # # # # ]: 0 : !time_change &&
453 [ # # # # ]: 0 : v->next_elapse < triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)) &&
454 [ # # # # ]: 0 : IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
455 : : /* This is a one time trigger, disable it now */
456 : 0 : v->disabled = true;
457 : 0 : continue;
458 : : }
459 : :
460 [ # # ]: 0 : if (!found_monotonic)
461 : 0 : t->next_elapse_monotonic_or_boottime = v->next_elapse;
462 : : else
463 : 0 : t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
464 : :
465 : 0 : found_monotonic = true;
466 : : }
467 : : }
468 : :
469 [ # # # # : 0 : if (!found_monotonic && !found_realtime && !t->on_timezone_change && !t->on_clock_change) {
# # # # ]
470 [ # # # # ]: 0 : log_unit_debug(UNIT(t), "Timer is elapsed.");
471 : 0 : timer_enter_elapsed(t, leave_around);
472 : 0 : return;
473 : : }
474 : :
475 [ # # ]: 0 : if (found_monotonic) {
476 : : char buf[FORMAT_TIMESPAN_MAX];
477 : : usec_t left;
478 : :
479 : 0 : add_random(t, &t->next_elapse_monotonic_or_boottime);
480 : :
481 [ # # # # ]: 0 : left = usec_sub_unsigned(t->next_elapse_monotonic_or_boottime, triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)));
482 [ # # # # ]: 0 : log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0));
483 : :
484 [ # # ]: 0 : if (t->monotonic_event_source) {
485 : 0 : r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
486 [ # # ]: 0 : if (r < 0)
487 : 0 : goto fail;
488 : :
489 : 0 : r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
490 [ # # ]: 0 : if (r < 0)
491 : 0 : goto fail;
492 : : } else {
493 : :
494 : 0 : r = sd_event_add_time(
495 [ # # ]: 0 : UNIT(t)->manager->event,
496 : : &t->monotonic_event_source,
497 [ # # ]: 0 : t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
498 : : t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
499 : : timer_dispatch, t);
500 [ # # ]: 0 : if (r < 0)
501 : 0 : goto fail;
502 : :
503 : 0 : (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
504 : : }
505 : :
506 [ # # ]: 0 : } else if (t->monotonic_event_source) {
507 : :
508 : 0 : r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
509 [ # # ]: 0 : if (r < 0)
510 : 0 : goto fail;
511 : : }
512 : :
513 [ # # ]: 0 : if (found_realtime) {
514 : : char buf[FORMAT_TIMESTAMP_MAX];
515 : :
516 : 0 : add_random(t, &t->next_elapse_realtime);
517 : :
518 [ # # # # ]: 0 : log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
519 : :
520 [ # # ]: 0 : if (t->realtime_event_source) {
521 : 0 : r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
522 [ # # ]: 0 : if (r < 0)
523 : 0 : goto fail;
524 : :
525 : 0 : r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
526 [ # # ]: 0 : if (r < 0)
527 : 0 : goto fail;
528 : : } else {
529 : 0 : r = sd_event_add_time(
530 [ # # ]: 0 : UNIT(t)->manager->event,
531 : : &t->realtime_event_source,
532 [ # # ]: 0 : t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
533 : : t->next_elapse_realtime, t->accuracy_usec,
534 : : timer_dispatch, t);
535 [ # # ]: 0 : if (r < 0)
536 : 0 : goto fail;
537 : :
538 : 0 : (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
539 : : }
540 : :
541 [ # # ]: 0 : } else if (t->realtime_event_source) {
542 : :
543 : 0 : r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
544 [ # # ]: 0 : if (r < 0)
545 : 0 : goto fail;
546 : : }
547 : :
548 : 0 : timer_set_state(t, TIMER_WAITING);
549 : 0 : return;
550 : :
551 : 0 : fail:
552 [ # # # # ]: 0 : log_unit_warning_errno(UNIT(t), r, "Failed to enter waiting state: %m");
553 : 0 : timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
554 : : }
555 : :
556 : 0 : static void timer_enter_running(Timer *t) {
557 [ # # ]: 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
558 : : Unit *trigger;
559 : : int r;
560 : :
561 [ # # ]: 0 : assert(t);
562 : :
563 : : /* Don't start job if we are supposed to go down */
564 [ # # # # ]: 0 : if (unit_stop_pending(UNIT(t)))
565 : 0 : return;
566 : :
567 [ # # ]: 0 : trigger = UNIT_TRIGGER(UNIT(t));
568 [ # # ]: 0 : if (!trigger) {
569 [ # # # # ]: 0 : log_unit_error(UNIT(t), "Unit to trigger vanished.");
570 : 0 : timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
571 : 0 : return;
572 : : }
573 : :
574 [ # # ]: 0 : r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
575 [ # # ]: 0 : if (r < 0)
576 : 0 : goto fail;
577 : :
578 : 0 : dual_timestamp_get(&t->last_trigger);
579 : :
580 [ # # ]: 0 : if (t->stamp_path)
581 : 0 : touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
582 : :
583 : 0 : timer_set_state(t, TIMER_RUNNING);
584 : 0 : return;
585 : :
586 : 0 : fail:
587 [ # # # # ]: 0 : log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
588 : 0 : timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
589 : : }
590 : :
591 : 0 : static int timer_start(Unit *u) {
592 : 0 : Timer *t = TIMER(u);
593 : : TimerValue *v;
594 : : int r;
595 : :
596 [ # # ]: 0 : assert(t);
597 [ # # # # ]: 0 : assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED));
598 : :
599 : 0 : r = unit_test_trigger_loaded(u);
600 [ # # ]: 0 : if (r < 0)
601 : 0 : return r;
602 : :
603 : 0 : r = unit_test_start_limit(u);
604 [ # # ]: 0 : if (r < 0) {
605 : 0 : timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
606 : 0 : return r;
607 : : }
608 : :
609 : 0 : r = unit_acquire_invocation_id(u);
610 [ # # ]: 0 : if (r < 0)
611 : 0 : return r;
612 : :
613 : 0 : t->last_trigger = DUAL_TIMESTAMP_NULL;
614 : :
615 : : /* Reenable all timers that depend on unit activation time */
616 [ # # ]: 0 : LIST_FOREACH(value, v, t->values)
617 [ # # ]: 0 : if (v->base == TIMER_ACTIVE)
618 : 0 : v->disabled = false;
619 : :
620 [ # # ]: 0 : if (t->stamp_path) {
621 : : struct stat st;
622 : :
623 [ # # ]: 0 : if (stat(t->stamp_path, &st) >= 0) {
624 : : usec_t ft;
625 : :
626 : : /* Load the file timestamp, but only if it is actually in the past. If it is in the future,
627 : : * something is wrong with the system clock. */
628 : :
629 : 0 : ft = timespec_load(&st.st_mtim);
630 [ # # ]: 0 : if (ft < now(CLOCK_REALTIME))
631 : 0 : t->last_trigger.realtime = ft;
632 : : else {
633 : : char z[FORMAT_TIMESTAMP_MAX];
634 : :
635 [ # # ]: 0 : log_unit_warning(u, "Not using persistent file timestamp %s as it is in the future.",
636 : : format_timestamp(z, sizeof(z), ft));
637 : : }
638 : :
639 [ # # ]: 0 : } else if (errno == ENOENT)
640 : : /* The timer has never run before,
641 : : * make sure a stamp file exists.
642 : : */
643 : 0 : (void) touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
644 : : }
645 : :
646 : 0 : t->result = TIMER_SUCCESS;
647 : 0 : timer_enter_waiting(t, false);
648 : 0 : return 1;
649 : : }
650 : :
651 : 0 : static int timer_stop(Unit *u) {
652 : 0 : Timer *t = TIMER(u);
653 : :
654 [ # # ]: 0 : assert(t);
655 [ # # # # ]: 0 : assert(IN_SET(t->state, TIMER_WAITING, TIMER_RUNNING, TIMER_ELAPSED));
656 : :
657 : 0 : timer_enter_dead(t, TIMER_SUCCESS);
658 : 0 : return 1;
659 : : }
660 : :
661 : 0 : static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
662 : 0 : Timer *t = TIMER(u);
663 : :
664 [ # # ]: 0 : assert(u);
665 [ # # ]: 0 : assert(f);
666 [ # # ]: 0 : assert(fds);
667 : :
668 : 0 : (void) serialize_item(f, "state", timer_state_to_string(t->state));
669 : 0 : (void) serialize_item(f, "result", timer_result_to_string(t->result));
670 : :
671 [ # # ]: 0 : if (t->last_trigger.realtime > 0)
672 : 0 : (void) serialize_usec(f, "last-trigger-realtime", t->last_trigger.realtime);
673 : :
674 [ # # ]: 0 : if (t->last_trigger.monotonic > 0)
675 : 0 : (void) serialize_usec(f, "last-trigger-monotonic", t->last_trigger.monotonic);
676 : :
677 : 0 : return 0;
678 : : }
679 : :
680 : 0 : static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
681 : 0 : Timer *t = TIMER(u);
682 : :
683 [ # # ]: 0 : assert(u);
684 [ # # ]: 0 : assert(key);
685 [ # # ]: 0 : assert(value);
686 [ # # ]: 0 : assert(fds);
687 : :
688 [ # # ]: 0 : if (streq(key, "state")) {
689 : : TimerState state;
690 : :
691 : 0 : state = timer_state_from_string(value);
692 [ # # ]: 0 : if (state < 0)
693 [ # # ]: 0 : log_unit_debug(u, "Failed to parse state value: %s", value);
694 : : else
695 : 0 : t->deserialized_state = state;
696 : :
697 [ # # ]: 0 : } else if (streq(key, "result")) {
698 : : TimerResult f;
699 : :
700 : 0 : f = timer_result_from_string(value);
701 [ # # ]: 0 : if (f < 0)
702 [ # # ]: 0 : log_unit_debug(u, "Failed to parse result value: %s", value);
703 [ # # ]: 0 : else if (f != TIMER_SUCCESS)
704 : 0 : t->result = f;
705 : :
706 [ # # ]: 0 : } else if (streq(key, "last-trigger-realtime"))
707 : 0 : (void) deserialize_usec(value, &t->last_trigger.realtime);
708 [ # # ]: 0 : else if (streq(key, "last-trigger-monotonic"))
709 : 0 : (void) deserialize_usec(value, &t->last_trigger.monotonic);
710 : : else
711 [ # # ]: 0 : log_unit_debug(u, "Unknown serialization key: %s", key);
712 : :
713 : 0 : return 0;
714 : : }
715 : :
716 : 0 : _pure_ static UnitActiveState timer_active_state(Unit *u) {
717 [ # # ]: 0 : assert(u);
718 : :
719 : 0 : return state_translation_table[TIMER(u)->state];
720 : : }
721 : :
722 : 0 : _pure_ static const char *timer_sub_state_to_string(Unit *u) {
723 [ # # ]: 0 : assert(u);
724 : :
725 : 0 : return timer_state_to_string(TIMER(u)->state);
726 : : }
727 : :
728 : 0 : static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
729 : 0 : Timer *t = TIMER(userdata);
730 : :
731 [ # # ]: 0 : assert(t);
732 : :
733 [ # # ]: 0 : if (t->state != TIMER_WAITING)
734 : 0 : return 0;
735 : :
736 [ # # # # ]: 0 : log_unit_debug(UNIT(t), "Timer elapsed.");
737 : 0 : timer_enter_running(t);
738 : 0 : return 0;
739 : : }
740 : :
741 : 0 : static void timer_trigger_notify(Unit *u, Unit *other) {
742 : 0 : Timer *t = TIMER(u);
743 : : TimerValue *v;
744 : :
745 [ # # ]: 0 : assert(u);
746 [ # # ]: 0 : assert(other);
747 : :
748 [ # # ]: 0 : if (other->load_state != UNIT_LOADED)
749 : 0 : return;
750 : :
751 : : /* Reenable all timers that depend on unit state */
752 [ # # ]: 0 : LIST_FOREACH(value, v, t->values)
753 [ # # # # ]: 0 : if (IN_SET(v->base, TIMER_UNIT_ACTIVE, TIMER_UNIT_INACTIVE))
754 : 0 : v->disabled = false;
755 : :
756 [ # # # # ]: 0 : switch (t->state) {
757 : :
758 : 0 : case TIMER_WAITING:
759 : : case TIMER_ELAPSED:
760 : :
761 : : /* Recalculate sleep time */
762 : 0 : timer_enter_waiting(t, false);
763 : 0 : break;
764 : :
765 : 0 : case TIMER_RUNNING:
766 : :
767 [ # # ]: 0 : if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
768 [ # # # # ]: 0 : log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
769 : 0 : timer_enter_waiting(t, false);
770 : : }
771 : 0 : break;
772 : :
773 : 0 : case TIMER_DEAD:
774 : : case TIMER_FAILED:
775 : 0 : break;
776 : :
777 : 0 : default:
778 : 0 : assert_not_reached("Unknown timer state");
779 : : }
780 : : }
781 : :
782 : 0 : static void timer_reset_failed(Unit *u) {
783 : 0 : Timer *t = TIMER(u);
784 : :
785 [ # # ]: 0 : assert(t);
786 : :
787 [ # # ]: 0 : if (t->state == TIMER_FAILED)
788 : 0 : timer_set_state(t, TIMER_DEAD);
789 : :
790 : 0 : t->result = TIMER_SUCCESS;
791 : 0 : }
792 : :
793 : 0 : static void timer_time_change(Unit *u) {
794 : 0 : Timer *t = TIMER(u);
795 : : usec_t ts;
796 : :
797 [ # # ]: 0 : assert(u);
798 : :
799 [ # # ]: 0 : if (t->state != TIMER_WAITING)
800 : 0 : return;
801 : :
802 : : /* If we appear to have triggered in the future, the system clock must
803 : : * have been set backwards. So let's rewind our own clock and allow
804 : : * the future trigger(s) to happen again :). Exactly the same as when
805 : : * you start a timer unit with Persistent=yes. */
806 : 0 : ts = now(CLOCK_REALTIME);
807 [ # # ]: 0 : if (t->last_trigger.realtime > ts)
808 : 0 : t->last_trigger.realtime = ts;
809 : :
810 [ # # ]: 0 : if (t->on_clock_change) {
811 [ # # ]: 0 : log_unit_debug(u, "Time change, triggering activation.");
812 : 0 : timer_enter_running(t);
813 : : } else {
814 [ # # ]: 0 : log_unit_debug(u, "Time change, recalculating next elapse.");
815 : 0 : timer_enter_waiting(t, true);
816 : : }
817 : : }
818 : :
819 : 0 : static void timer_timezone_change(Unit *u) {
820 : 0 : Timer *t = TIMER(u);
821 : :
822 [ # # ]: 0 : assert(u);
823 : :
824 [ # # ]: 0 : if (t->state != TIMER_WAITING)
825 : 0 : return;
826 : :
827 [ # # ]: 0 : if (t->on_timezone_change) {
828 [ # # ]: 0 : log_unit_debug(u, "Timezone change, triggering activation.");
829 : 0 : timer_enter_running(t);
830 : : } else {
831 [ # # ]: 0 : log_unit_debug(u, "Timezone change, recalculating next elapse.");
832 : 0 : timer_enter_waiting(t, false);
833 : : }
834 : : }
835 : :
836 : 0 : static int timer_clean(Unit *u, ExecCleanMask mask) {
837 : 0 : Timer *t = TIMER(u);
838 : : int r;
839 : :
840 [ # # ]: 0 : assert(t);
841 [ # # ]: 0 : assert(mask != 0);
842 : :
843 [ # # ]: 0 : if (t->state != TIMER_DEAD)
844 : 0 : return -EBUSY;
845 : :
846 [ # # # # ]: 0 : if (!IN_SET(mask, EXEC_CLEAN_STATE))
847 : 0 : return -EUNATCH;
848 : :
849 : 0 : r = timer_setup_persistent(t);
850 [ # # ]: 0 : if (r < 0)
851 : 0 : return r;
852 : :
853 [ # # ]: 0 : if (!t->stamp_path)
854 : 0 : return -EUNATCH;
855 : :
856 [ # # # # ]: 0 : if (unlink(t->stamp_path) && errno != ENOENT)
857 [ # # ]: 0 : return log_unit_error_errno(u, errno, "Failed to clean stamp file of timer: %m");
858 : :
859 : 0 : return 0;
860 : : }
861 : :
862 : 0 : static int timer_can_clean(Unit *u, ExecCleanMask *ret) {
863 : 0 : Timer *t = TIMER(u);
864 : :
865 [ # # ]: 0 : assert(t);
866 : :
867 [ # # ]: 0 : *ret = t->persistent ? EXEC_CLEAN_STATE : 0;
868 : 0 : return 0;
869 : : }
870 : :
871 : : static const char* const timer_base_table[_TIMER_BASE_MAX] = {
872 : : [TIMER_ACTIVE] = "OnActiveSec",
873 : : [TIMER_BOOT] = "OnBootSec",
874 : : [TIMER_STARTUP] = "OnStartupSec",
875 : : [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
876 : : [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
877 : : [TIMER_CALENDAR] = "OnCalendar"
878 : : };
879 : :
880 [ + + + + ]: 64 : DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
881 : :
882 : : static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
883 : : [TIMER_SUCCESS] = "success",
884 : : [TIMER_FAILURE_RESOURCES] = "resources",
885 : : [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
886 : : };
887 : :
888 [ + + + + ]: 40 : DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
889 : :
890 : : const UnitVTable timer_vtable = {
891 : : .object_size = sizeof(Timer),
892 : :
893 : : .sections =
894 : : "Unit\0"
895 : : "Timer\0"
896 : : "Install\0",
897 : : .private_section = "Timer",
898 : :
899 : : .init = timer_init,
900 : : .done = timer_done,
901 : : .load = timer_load,
902 : :
903 : : .coldplug = timer_coldplug,
904 : :
905 : : .dump = timer_dump,
906 : :
907 : : .start = timer_start,
908 : : .stop = timer_stop,
909 : :
910 : : .clean = timer_clean,
911 : : .can_clean = timer_can_clean,
912 : :
913 : : .serialize = timer_serialize,
914 : : .deserialize_item = timer_deserialize_item,
915 : :
916 : : .active_state = timer_active_state,
917 : : .sub_state_to_string = timer_sub_state_to_string,
918 : :
919 : : .trigger_notify = timer_trigger_notify,
920 : :
921 : : .reset_failed = timer_reset_failed,
922 : : .time_change = timer_time_change,
923 : : .timezone_change = timer_timezone_change,
924 : :
925 : : .bus_vtable = bus_timer_vtable,
926 : : .bus_set_property = bus_timer_set_property,
927 : :
928 : : .can_transient = true,
929 : : };
|