]>
Commit | Line | Data |
---|---|---|
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" |
398ef8ba | 29 | #include "bus-errors.h" |
871d7de4 LP |
30 | |
31 | static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { | |
32 | [TIMER_DEAD] = UNIT_INACTIVE, | |
33 | [TIMER_WAITING] = UNIT_ACTIVE, | |
34 | [TIMER_RUNNING] = UNIT_ACTIVE, | |
35 | [TIMER_ELAPSED] = UNIT_ACTIVE, | |
fdf20a31 | 36 | [TIMER_FAILED] = UNIT_FAILED |
871d7de4 LP |
37 | }; |
38 | ||
39 | static void timer_init(Unit *u) { | |
40 | Timer *t = TIMER(u); | |
41 | ||
42 | assert(u); | |
ac155bb8 | 43 | assert(u->load_state == UNIT_STUB); |
871d7de4 | 44 | |
36697dc0 LP |
45 | t->next_elapse_monotonic = (usec_t) -1; |
46 | t->next_elapse_realtime = (usec_t) -1; | |
47 | watch_init(&t->monotonic_watch); | |
48 | watch_init(&t->realtime_watch); | |
871d7de4 | 49 | } |
5cb5a6ff | 50 | |
87f0e418 LP |
51 | static void timer_done(Unit *u) { |
52 | Timer *t = TIMER(u); | |
871d7de4 LP |
53 | TimerValue *v; |
54 | ||
55 | assert(t); | |
56 | ||
57 | while ((v = t->values)) { | |
58 | LIST_REMOVE(TimerValue, value, t->values, v); | |
36697dc0 LP |
59 | |
60 | if (v->calendar_spec) | |
61 | calendar_spec_free(v->calendar_spec); | |
62 | ||
871d7de4 LP |
63 | free(v); |
64 | } | |
65 | ||
36697dc0 LP |
66 | unit_unwatch_timer(u, &t->monotonic_watch); |
67 | unit_unwatch_timer(u, &t->realtime_watch); | |
57020a3a LP |
68 | |
69 | unit_ref_unset(&t->unit); | |
871d7de4 LP |
70 | } |
71 | ||
72 | static int timer_verify(Timer *t) { | |
73 | assert(t); | |
74 | ||
1124fe6f | 75 | if (UNIT(t)->load_state != UNIT_LOADED) |
871d7de4 LP |
76 | return 0; |
77 | ||
78 | if (!t->values) { | |
1124fe6f | 79 | log_error("%s lacks value setting. Refusing.", UNIT(t)->id); |
871d7de4 LP |
80 | return -EINVAL; |
81 | } | |
82 | ||
83 | return 0; | |
84 | } | |
85 | ||
6c155fe3 LP |
86 | static int timer_add_default_dependencies(Timer *t) { |
87 | int r; | |
88 | ||
89 | assert(t); | |
90 | ||
67445f4e | 91 | if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) { |
36697dc0 LP |
92 | r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true); |
93 | if (r < 0) | |
2a77d31d LP |
94 | return r; |
95 | ||
36697dc0 LP |
96 | r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); |
97 | if (r < 0) | |
6c155fe3 | 98 | return r; |
2a77d31d | 99 | } |
6c155fe3 | 100 | |
ead8e478 | 101 | return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); |
6c155fe3 LP |
102 | } |
103 | ||
871d7de4 LP |
104 | static int timer_load(Unit *u) { |
105 | Timer *t = TIMER(u); | |
106 | int r; | |
107 | ||
108 | assert(u); | |
ac155bb8 | 109 | assert(u->load_state == UNIT_STUB); |
871d7de4 | 110 | |
36697dc0 LP |
111 | r = unit_load_fragment_and_dropin(u); |
112 | if (r < 0) | |
871d7de4 LP |
113 | return r; |
114 | ||
ac155bb8 | 115 | if (u->load_state == UNIT_LOADED) { |
871d7de4 | 116 | |
57020a3a LP |
117 | if (!UNIT_DEREF(t->unit)) { |
118 | Unit *x; | |
119 | ||
120 | r = unit_load_related_unit(u, ".service", &x); | |
121 | if (r < 0) | |
871d7de4 LP |
122 | return r; |
123 | ||
57020a3a LP |
124 | unit_ref_set(&t->unit, x); |
125 | } | |
126 | ||
127 | r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(t->unit), true); | |
128 | if (r < 0) | |
871d7de4 | 129 | return r; |
a40eb732 | 130 | |
36697dc0 LP |
131 | if (UNIT(t)->default_dependencies) { |
132 | r = timer_add_default_dependencies(t); | |
133 | if (r < 0) | |
a40eb732 | 134 | return r; |
36697dc0 | 135 | } |
871d7de4 LP |
136 | } |
137 | ||
138 | return timer_verify(t); | |
139 | } | |
140 | ||
141 | static void timer_dump(Unit *u, FILE *f, const char *prefix) { | |
142 | Timer *t = TIMER(u); | |
871d7de4 | 143 | TimerValue *v; |
034c6ed7 | 144 | |
871d7de4 LP |
145 | fprintf(f, |
146 | "%sTimer State: %s\n" | |
067d72c9 | 147 | "%sResult: %s\n" |
871d7de4 LP |
148 | "%sUnit: %s\n", |
149 | prefix, timer_state_to_string(t->state), | |
067d72c9 | 150 | prefix, timer_result_to_string(t->result), |
ac155bb8 | 151 | prefix, UNIT_DEREF(t->unit)->id); |
871d7de4 | 152 | |
36697dc0 LP |
153 | LIST_FOREACH(value, v, t->values) { |
154 | ||
155 | if (v->base == TIMER_CALENDAR) { | |
156 | _cleanup_free_ char *p = NULL; | |
157 | ||
158 | calendar_spec_to_string(v->calendar_spec, &p); | |
159 | ||
160 | fprintf(f, | |
161 | "%s%s: %s\n", | |
162 | prefix, | |
163 | timer_base_to_string(v->base), | |
164 | strna(p)); | |
165 | } else { | |
166 | char timespan1[FORMAT_TIMESPAN_MAX]; | |
167 | ||
168 | fprintf(f, | |
169 | "%s%s: %s\n", | |
170 | prefix, | |
171 | timer_base_to_string(v->base), | |
172 | strna(format_timespan(timespan1, sizeof(timespan1), v->value))); | |
173 | } | |
174 | } | |
871d7de4 LP |
175 | } |
176 | ||
177 | static void timer_set_state(Timer *t, TimerState state) { | |
178 | TimerState old_state; | |
034c6ed7 | 179 | assert(t); |
871d7de4 LP |
180 | |
181 | old_state = t->state; | |
182 | t->state = state; | |
183 | ||
36697dc0 LP |
184 | if (state != TIMER_WAITING) { |
185 | unit_unwatch_timer(UNIT(t), &t->monotonic_watch); | |
186 | unit_unwatch_timer(UNIT(t), &t->realtime_watch); | |
187 | } | |
871d7de4 LP |
188 | |
189 | if (state != old_state) | |
190 | log_debug("%s changed %s -> %s", | |
1124fe6f | 191 | UNIT(t)->id, |
871d7de4 LP |
192 | timer_state_to_string(old_state), |
193 | timer_state_to_string(state)); | |
194 | ||
e2f3b44c | 195 | unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true); |
871d7de4 LP |
196 | } |
197 | ||
198 | static void timer_enter_waiting(Timer *t, bool initial); | |
199 | ||
200 | static int timer_coldplug(Unit *u) { | |
201 | Timer *t = TIMER(u); | |
202 | ||
203 | assert(t); | |
204 | assert(t->state == TIMER_DEAD); | |
205 | ||
206 | if (t->deserialized_state != t->state) { | |
207 | ||
b363ca6f | 208 | if (t->deserialized_state == TIMER_WAITING) |
871d7de4 LP |
209 | timer_enter_waiting(t, false); |
210 | else | |
211 | timer_set_state(t, t->deserialized_state); | |
212 | } | |
213 | ||
214 | return 0; | |
215 | } | |
216 | ||
067d72c9 | 217 | static void timer_enter_dead(Timer *t, TimerResult f) { |
871d7de4 LP |
218 | assert(t); |
219 | ||
067d72c9 LP |
220 | if (f != TIMER_SUCCESS) |
221 | t->result = f; | |
871d7de4 | 222 | |
067d72c9 | 223 | timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD); |
871d7de4 LP |
224 | } |
225 | ||
226 | static void timer_enter_waiting(Timer *t, bool initial) { | |
227 | TimerValue *v; | |
36697dc0 LP |
228 | usec_t base = 0; |
229 | dual_timestamp ts; | |
230 | bool found_monotonic = false, found_realtime = false; | |
871d7de4 LP |
231 | int r; |
232 | ||
36697dc0 LP |
233 | dual_timestamp_get(&ts); |
234 | t->next_elapse_monotonic = t->next_elapse_realtime = 0; | |
871d7de4 LP |
235 | |
236 | LIST_FOREACH(value, v, t->values) { | |
237 | ||
238 | if (v->disabled) | |
239 | continue; | |
240 | ||
36697dc0 LP |
241 | if (v->base == TIMER_CALENDAR) { |
242 | ||
243 | r = calendar_spec_next_usec(v->calendar_spec, ts.realtime, &v->next_elapse); | |
244 | if (r < 0) | |
245 | continue; | |
246 | ||
247 | if (!initial && v->next_elapse < ts.realtime) { | |
248 | v->disabled = true; | |
249 | continue; | |
250 | } | |
871d7de4 | 251 | |
36697dc0 LP |
252 | if (!found_realtime) |
253 | t->next_elapse_realtime = v->next_elapse; | |
10717a1a | 254 | else |
36697dc0 | 255 | t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse); |
871d7de4 | 256 | |
36697dc0 | 257 | found_realtime = true; |
871d7de4 | 258 | |
36697dc0 LP |
259 | } else { |
260 | switch (v->base) { | |
871d7de4 | 261 | |
36697dc0 LP |
262 | case TIMER_ACTIVE: |
263 | if (state_translation_table[t->state] == UNIT_ACTIVE) | |
264 | base = UNIT(t)->inactive_exit_timestamp.monotonic; | |
265 | else | |
266 | base = ts.monotonic; | |
267 | break; | |
871d7de4 | 268 | |
36697dc0 LP |
269 | case TIMER_BOOT: |
270 | /* CLOCK_MONOTONIC equals the uptime on Linux */ | |
271 | base = 0; | |
272 | break; | |
871d7de4 | 273 | |
36697dc0 LP |
274 | case TIMER_STARTUP: |
275 | base = UNIT(t)->manager->userspace_timestamp.monotonic; | |
276 | break; | |
871d7de4 | 277 | |
36697dc0 | 278 | case TIMER_UNIT_ACTIVE: |
871d7de4 | 279 | |
36697dc0 LP |
280 | if (UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic <= 0) |
281 | continue; | |
871d7de4 | 282 | |
36697dc0 LP |
283 | base = UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic; |
284 | break; | |
871d7de4 | 285 | |
36697dc0 | 286 | case TIMER_UNIT_INACTIVE: |
871d7de4 | 287 | |
36697dc0 LP |
288 | if (UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic <= 0) |
289 | continue; | |
871d7de4 | 290 | |
36697dc0 LP |
291 | base = UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic; |
292 | break; | |
871d7de4 | 293 | |
36697dc0 LP |
294 | default: |
295 | assert_not_reached("Unknown timer base"); | |
296 | } | |
871d7de4 | 297 | |
36697dc0 LP |
298 | v->next_elapse = base + v->value; |
299 | ||
300 | if (!initial && v->next_elapse < ts.monotonic) { | |
301 | v->disabled = true; | |
302 | continue; | |
303 | } | |
304 | ||
305 | if (!found_monotonic) | |
306 | t->next_elapse_monotonic = v->next_elapse; | |
307 | else | |
308 | t->next_elapse_monotonic = MIN(t->next_elapse_monotonic, v->next_elapse); | |
309 | ||
310 | found_monotonic = true; | |
311 | } | |
871d7de4 LP |
312 | } |
313 | ||
36697dc0 LP |
314 | if (!found_monotonic && !found_realtime) { |
315 | log_debug("%s: Timer is elapsed.", UNIT(t)->id); | |
871d7de4 LP |
316 | timer_set_state(t, TIMER_ELAPSED); |
317 | return; | |
318 | } | |
319 | ||
36697dc0 LP |
320 | if (found_monotonic) { |
321 | char buf[FORMAT_TIMESPAN_MAX]; | |
322 | log_debug("%s: Monotonic timer elapses in %s the next time.", UNIT(t)->id, format_timespan(buf, sizeof(buf), t->next_elapse_monotonic - ts.monotonic)); | |
871d7de4 | 323 | |
36697dc0 LP |
324 | r = unit_watch_timer(UNIT(t), CLOCK_MONOTONIC, false, t->next_elapse_monotonic, &t->monotonic_watch); |
325 | if (r < 0) | |
326 | goto fail; | |
327 | } else | |
328 | unit_unwatch_timer(UNIT(t), &t->monotonic_watch); | |
329 | ||
330 | if (found_realtime) { | |
331 | char buf[FORMAT_TIMESTAMP_MAX]; | |
332 | log_debug("%s: Realtime timer elapses at %s the next time.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime)); | |
333 | ||
334 | r = unit_watch_timer(UNIT(t), CLOCK_REALTIME, false, t->next_elapse_realtime, &t->realtime_watch); | |
335 | if (r < 0) | |
336 | goto fail; | |
337 | } else | |
338 | unit_unwatch_timer(UNIT(t), &t->realtime_watch); | |
871d7de4 LP |
339 | |
340 | timer_set_state(t, TIMER_WAITING); | |
341 | return; | |
342 | ||
343 | fail: | |
1124fe6f | 344 | log_warning("%s failed to enter waiting state: %s", UNIT(t)->id, strerror(-r)); |
067d72c9 | 345 | timer_enter_dead(t, TIMER_FAILURE_RESOURCES); |
871d7de4 LP |
346 | } |
347 | ||
348 | static void timer_enter_running(Timer *t) { | |
398ef8ba | 349 | DBusError error; |
871d7de4 | 350 | int r; |
398ef8ba | 351 | |
871d7de4 | 352 | assert(t); |
398ef8ba | 353 | dbus_error_init(&error); |
871d7de4 | 354 | |
ba3e67a7 | 355 | /* Don't start job if we are supposed to go down */ |
1124fe6f | 356 | if (UNIT(t)->job && UNIT(t)->job->type == JOB_STOP) |
ba3e67a7 LP |
357 | return; |
358 | ||
36697dc0 LP |
359 | r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_DEREF(t->unit), JOB_REPLACE, true, &error, NULL); |
360 | if (r < 0) | |
871d7de4 LP |
361 | goto fail; |
362 | ||
363 | timer_set_state(t, TIMER_RUNNING); | |
364 | return; | |
365 | ||
366 | fail: | |
1124fe6f | 367 | log_warning("%s failed to queue unit startup job: %s", UNIT(t)->id, bus_error(&error, r)); |
067d72c9 | 368 | timer_enter_dead(t, TIMER_FAILURE_RESOURCES); |
398ef8ba LP |
369 | |
370 | dbus_error_free(&error); | |
871d7de4 LP |
371 | } |
372 | ||
373 | static int timer_start(Unit *u) { | |
374 | Timer *t = TIMER(u); | |
375 | ||
376 | assert(t); | |
fdf20a31 | 377 | assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED); |
01f78473 | 378 | |
ac155bb8 | 379 | if (UNIT_DEREF(t->unit)->load_state != UNIT_LOADED) |
01f78473 | 380 | return -ENOENT; |
871d7de4 | 381 | |
067d72c9 | 382 | t->result = TIMER_SUCCESS; |
871d7de4 LP |
383 | timer_enter_waiting(t, true); |
384 | return 0; | |
385 | } | |
386 | ||
387 | static int timer_stop(Unit *u) { | |
388 | Timer *t = TIMER(u); | |
389 | ||
390 | assert(t); | |
391 | assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED); | |
392 | ||
067d72c9 | 393 | timer_enter_dead(t, TIMER_SUCCESS); |
871d7de4 LP |
394 | return 0; |
395 | } | |
396 | ||
397 | static int timer_serialize(Unit *u, FILE *f, FDSet *fds) { | |
398 | Timer *t = TIMER(u); | |
399 | ||
400 | assert(u); | |
401 | assert(f); | |
402 | assert(fds); | |
403 | ||
404 | unit_serialize_item(u, f, "state", timer_state_to_string(t->state)); | |
067d72c9 | 405 | unit_serialize_item(u, f, "result", timer_result_to_string(t->result)); |
871d7de4 LP |
406 | |
407 | return 0; | |
408 | } | |
409 | ||
410 | static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { | |
411 | Timer *t = TIMER(u); | |
412 | ||
413 | assert(u); | |
414 | assert(key); | |
415 | assert(value); | |
416 | assert(fds); | |
417 | ||
418 | if (streq(key, "state")) { | |
419 | TimerState state; | |
420 | ||
36697dc0 LP |
421 | state = timer_state_from_string(value); |
422 | if (state < 0) | |
871d7de4 LP |
423 | log_debug("Failed to parse state value %s", value); |
424 | else | |
425 | t->deserialized_state = state; | |
067d72c9 LP |
426 | } else if (streq(key, "result")) { |
427 | TimerResult f; | |
428 | ||
429 | f = timer_result_from_string(value); | |
430 | if (f < 0) | |
431 | log_debug("Failed to parse result value %s", value); | |
432 | else if (f != TIMER_SUCCESS) | |
433 | t->result = f; | |
434 | ||
871d7de4 LP |
435 | } else |
436 | log_debug("Unknown serialization key '%s'", key); | |
437 | ||
438 | return 0; | |
034c6ed7 LP |
439 | } |
440 | ||
87f0e418 | 441 | static UnitActiveState timer_active_state(Unit *u) { |
871d7de4 LP |
442 | assert(u); |
443 | ||
444 | return state_translation_table[TIMER(u)->state]; | |
445 | } | |
446 | ||
447 | static const char *timer_sub_state_to_string(Unit *u) { | |
448 | assert(u); | |
449 | ||
450 | return timer_state_to_string(TIMER(u)->state); | |
451 | } | |
452 | ||
453 | static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) { | |
454 | Timer *t = TIMER(u); | |
455 | ||
456 | assert(t); | |
457 | assert(elapsed == 1); | |
5cb5a6ff | 458 | |
871d7de4 LP |
459 | if (t->state != TIMER_WAITING) |
460 | return; | |
5cb5a6ff | 461 | |
ac155bb8 | 462 | log_debug("Timer elapsed on %s", u->id); |
871d7de4 | 463 | timer_enter_running(t); |
5cb5a6ff LP |
464 | } |
465 | ||
871d7de4 | 466 | void timer_unit_notify(Unit *u, UnitActiveState new_state) { |
871d7de4 | 467 | Iterator i; |
57020a3a | 468 | Unit *k; |
871d7de4 | 469 | |
ac155bb8 | 470 | if (u->type == UNIT_TIMER) |
871d7de4 LP |
471 | return; |
472 | ||
ac155bb8 | 473 | SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) { |
871d7de4 LP |
474 | Timer *t; |
475 | TimerValue *v; | |
476 | ||
ac155bb8 | 477 | if (k->type != UNIT_TIMER) |
871d7de4 LP |
478 | continue; |
479 | ||
ac155bb8 | 480 | if (k->load_state != UNIT_LOADED) |
01f78473 LP |
481 | continue; |
482 | ||
57020a3a | 483 | t = TIMER(k); |
871d7de4 LP |
484 | |
485 | /* Reenable all timers that depend on unit state */ | |
486 | LIST_FOREACH(value, v, t->values) | |
487 | if (v->base == TIMER_UNIT_ACTIVE || | |
488 | v->base == TIMER_UNIT_INACTIVE) | |
489 | v->disabled = false; | |
490 | ||
491 | switch (t->state) { | |
492 | ||
493 | case TIMER_WAITING: | |
494 | case TIMER_ELAPSED: | |
495 | ||
496 | /* Recalculate sleep time */ | |
497 | timer_enter_waiting(t, false); | |
498 | break; | |
499 | ||
500 | case TIMER_RUNNING: | |
501 | ||
fdf20a31 | 502 | if (UNIT_IS_INACTIVE_OR_FAILED(new_state)) { |
1124fe6f | 503 | log_debug("%s got notified about unit deactivation.", UNIT(t)->id); |
871d7de4 LP |
504 | timer_enter_waiting(t, false); |
505 | } | |
506 | ||
507 | break; | |
508 | ||
509 | case TIMER_DEAD: | |
fdf20a31 | 510 | case TIMER_FAILED: |
0b021426 | 511 | break; |
871d7de4 LP |
512 | |
513 | default: | |
514 | assert_not_reached("Unknown timer state"); | |
515 | } | |
516 | } | |
871d7de4 LP |
517 | } |
518 | ||
fdf20a31 | 519 | static void timer_reset_failed(Unit *u) { |
5632e374 LP |
520 | Timer *t = TIMER(u); |
521 | ||
522 | assert(t); | |
523 | ||
fdf20a31 | 524 | if (t->state == TIMER_FAILED) |
5632e374 LP |
525 | timer_set_state(t, TIMER_DEAD); |
526 | ||
067d72c9 | 527 | t->result = TIMER_SUCCESS; |
5632e374 LP |
528 | } |
529 | ||
8742514c LP |
530 | static void timer_time_change(Unit *u) { |
531 | Timer *t = TIMER(u); | |
532 | ||
533 | assert(u); | |
534 | ||
535 | if (t->state != TIMER_WAITING) | |
536 | return; | |
537 | ||
538 | log_info("%s: time change, recalculating next elapse.", u->id); | |
539 | timer_enter_waiting(t, false); | |
540 | } | |
541 | ||
871d7de4 LP |
542 | static const char* const timer_state_table[_TIMER_STATE_MAX] = { |
543 | [TIMER_DEAD] = "dead", | |
544 | [TIMER_WAITING] = "waiting", | |
545 | [TIMER_RUNNING] = "running", | |
546 | [TIMER_ELAPSED] = "elapsed", | |
fdf20a31 | 547 | [TIMER_FAILED] = "failed" |
871d7de4 LP |
548 | }; |
549 | ||
550 | DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); | |
551 | ||
552 | static const char* const timer_base_table[_TIMER_BASE_MAX] = { | |
03fae018 LP |
553 | [TIMER_ACTIVE] = "OnActiveSec", |
554 | [TIMER_BOOT] = "OnBootSec", | |
555 | [TIMER_STARTUP] = "OnStartupSec", | |
556 | [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec", | |
36697dc0 LP |
557 | [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec", |
558 | [TIMER_CALENDAR] = "OnCalendar" | |
871d7de4 LP |
559 | }; |
560 | ||
561 | DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); | |
562 | ||
067d72c9 LP |
563 | static const char* const timer_result_table[_TIMER_RESULT_MAX] = { |
564 | [TIMER_SUCCESS] = "success", | |
565 | [TIMER_FAILURE_RESOURCES] = "resources" | |
566 | }; | |
567 | ||
568 | DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult); | |
569 | ||
87f0e418 | 570 | const UnitVTable timer_vtable = { |
7d17cfbc | 571 | .object_size = sizeof(Timer), |
f975e971 LP |
572 | .sections = |
573 | "Unit\0" | |
574 | "Timer\0" | |
575 | "Install\0", | |
5cb5a6ff | 576 | |
871d7de4 | 577 | .init = timer_init, |
034c6ed7 | 578 | .done = timer_done, |
871d7de4 LP |
579 | .load = timer_load, |
580 | ||
581 | .coldplug = timer_coldplug, | |
582 | ||
583 | .dump = timer_dump, | |
584 | ||
585 | .start = timer_start, | |
586 | .stop = timer_stop, | |
587 | ||
588 | .serialize = timer_serialize, | |
589 | .deserialize_item = timer_deserialize_item, | |
590 | ||
591 | .active_state = timer_active_state, | |
592 | .sub_state_to_string = timer_sub_state_to_string, | |
593 | ||
594 | .timer_event = timer_timer_event, | |
5cb5a6ff | 595 | |
fdf20a31 | 596 | .reset_failed = timer_reset_failed, |
8742514c | 597 | .time_change = timer_time_change, |
5632e374 | 598 | |
c4e2ceae LP |
599 | .bus_interface = "org.freedesktop.systemd1.Timer", |
600 | .bus_message_handler = bus_timer_message_handler, | |
601 | .bus_invalidating_properties = bus_timer_invalidating_properties | |
5cb5a6ff | 602 | }; |