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