chiark / gitweb /
rtnl: drop "sd_" prefix from cleanup macros
[elogind.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-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 static void timer_init(Unit *u) {
43         Timer *t = TIMER(u);
44
45         assert(u);
46         assert(u->load_state == UNIT_STUB);
47
48         t->next_elapse_monotonic = (usec_t) -1;
49         t->next_elapse_realtime = (usec_t) -1;
50         t->accuracy_usec = USEC_PER_MINUTE;
51 }
52
53 void timer_free_values(Timer *t) {
54         TimerValue *v;
55
56         assert(t);
57
58         while ((v = t->values)) {
59                 LIST_REMOVE(value, t->values, v);
60
61                 if (v->calendar_spec)
62                         calendar_spec_free(v->calendar_spec);
63
64                 free(v);
65         }
66 }
67
68 static void timer_done(Unit *u) {
69         Timer *t = TIMER(u);
70
71         assert(t);
72
73         timer_free_values(t);
74
75         t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
76         t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
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         r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
100         if (r < 0)
101                 return r;
102
103         if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
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 (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
126                         Unit *x;
127
128                         r = unit_load_related_unit(u, ".service", &x);
129                         if (r < 0)
130                                 return r;
131
132                         r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
133                         if (r < 0)
134                                 return r;
135                 }
136
137                 if (UNIT(t)->default_dependencies) {
138                         r = timer_add_default_dependencies(t);
139                         if (r < 0)
140                                 return r;
141                 }
142         }
143
144         return timer_verify(t);
145 }
146
147 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
148         char buf[FORMAT_TIMESPAN_MAX];
149         Timer *t = TIMER(u);
150         Unit *trigger;
151         TimerValue *v;
152
153         trigger = UNIT_TRIGGER(u);
154
155         fprintf(f,
156                 "%sTimer State: %s\n"
157                 "%sResult: %s\n"
158                 "%sUnit: %s\n"
159                 "%sAccuracy: %s\n",
160                 prefix, timer_state_to_string(t->state),
161                 prefix, timer_result_to_string(t->result),
162                 prefix, trigger ? trigger->id : "n/a",
163                 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
164
165         LIST_FOREACH(value, v, t->values) {
166
167                 if (v->base == TIMER_CALENDAR) {
168                         _cleanup_free_ char *p = NULL;
169
170                         calendar_spec_to_string(v->calendar_spec, &p);
171
172                         fprintf(f,
173                                 "%s%s: %s\n",
174                                 prefix,
175                                 timer_base_to_string(v->base),
176                                 strna(p));
177                 } else  {
178                         char timespan1[FORMAT_TIMESPAN_MAX];
179
180                         fprintf(f,
181                                 "%s%s: %s\n",
182                                 prefix,
183                                 timer_base_to_string(v->base),
184                                 strna(format_timespan(timespan1, sizeof(timespan1), v->value, 0)));
185                 }
186         }
187 }
188
189 static void timer_set_state(Timer *t, TimerState state) {
190         TimerState old_state;
191         assert(t);
192
193         old_state = t->state;
194         t->state = state;
195
196         if (state != TIMER_WAITING) {
197                 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
198                 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
199         }
200
201         if (state != old_state)
202                 log_debug_unit(UNIT(t)->id,
203                                "%s changed %s -> %s", UNIT(t)->id,
204                                timer_state_to_string(old_state),
205                                timer_state_to_string(state));
206
207         unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
208 }
209
210 static void timer_enter_waiting(Timer *t, bool initial);
211
212 static int timer_coldplug(Unit *u) {
213         Timer *t = TIMER(u);
214
215         assert(t);
216         assert(t->state == TIMER_DEAD);
217
218         if (t->deserialized_state != t->state) {
219
220                 if (t->deserialized_state == TIMER_WAITING)
221                         timer_enter_waiting(t, false);
222                 else
223                         timer_set_state(t, t->deserialized_state);
224         }
225
226         return 0;
227 }
228
229 static void timer_enter_dead(Timer *t, TimerResult f) {
230         assert(t);
231
232         if (f != TIMER_SUCCESS)
233                 t->result = f;
234
235         timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
236 }
237
238
239 static void timer_enter_waiting(Timer *t, bool initial) {
240         TimerValue *v;
241         usec_t base = 0;
242         dual_timestamp ts;
243         bool found_monotonic = false, found_realtime = false;
244         int r;
245
246         dual_timestamp_get(&ts);
247         t->next_elapse_monotonic = t->next_elapse_realtime = 0;
248
249         LIST_FOREACH(value, v, t->values) {
250
251                 if (v->disabled)
252                         continue;
253
254                 if (v->base == TIMER_CALENDAR) {
255
256                         r = calendar_spec_next_usec(v->calendar_spec, ts.realtime, &v->next_elapse);
257                         if (r < 0)
258                                 continue;
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                                 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
289
290                                 if (base <= 0)
291                                         base = t->last_trigger_monotonic;
292
293                                 if (base <= 0)
294                                         continue;
295
296                                 break;
297
298                         case TIMER_UNIT_INACTIVE:
299
300                                 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
301
302                                 if (base <= 0)
303                                         base = t->last_trigger_monotonic;
304
305                                 if (base <= 0)
306                                         continue;
307
308                                 break;
309
310                         default:
311                                 assert_not_reached("Unknown timer base");
312                         }
313
314                         v->next_elapse = base + v->value;
315
316                         if (!initial &&
317                             v->next_elapse < ts.monotonic &&
318                             (v->base == TIMER_ACTIVE || v->base == TIMER_BOOT || v->base == TIMER_STARTUP)) {
319                                 /* This is a one time trigger, disable it now */
320                                 v->disabled = true;
321                                 continue;
322                         }
323
324                         if (!found_monotonic)
325                                 t->next_elapse_monotonic = v->next_elapse;
326                         else
327                                 t->next_elapse_monotonic = MIN(t->next_elapse_monotonic, v->next_elapse);
328
329                         found_monotonic = true;
330                 }
331         }
332
333         if (!found_monotonic && !found_realtime) {
334                 log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
335                 timer_set_state(t, TIMER_ELAPSED);
336                 return;
337         }
338
339         if (found_monotonic) {
340                 char buf[FORMAT_TIMESPAN_MAX];
341                 log_debug_unit(UNIT(t)->id,
342                                "%s: Monotonic timer elapses in %s.",
343                                UNIT(t)->id,
344                                format_timespan(buf, sizeof(buf), t->next_elapse_monotonic > ts.monotonic ? t->next_elapse_monotonic - ts.monotonic : 0, 0));
345
346                 if (t->monotonic_event_source) {
347                         r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic);
348                         if (r < 0)
349                                 goto fail;
350
351                         r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
352                 } else
353                         r = sd_event_add_monotonic(UNIT(t)->manager->event, t->next_elapse_monotonic, t->accuracy_usec, timer_dispatch, t, &t->monotonic_event_source);
354
355                 if (r < 0)
356                         goto fail;
357
358         } else if (t->monotonic_event_source) {
359                 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
360
361                 if (r < 0)
362                         goto fail;
363         }
364
365         if (found_realtime) {
366                 char buf[FORMAT_TIMESTAMP_MAX];
367                 log_debug_unit(UNIT(t)->id,
368                                "%s: Realtime timer elapses at %s.",
369                                UNIT(t)->id,
370                                format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
371
372                 if (t->realtime_event_source) {
373                         r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
374                         if (r < 0)
375                                 goto fail;
376
377                         r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
378                 } else
379                         r = sd_event_add_realtime(UNIT(t)->manager->event, t->next_elapse_realtime, t->accuracy_usec, timer_dispatch, t, &t->realtime_event_source);
380
381                 if (r < 0)
382                         goto fail;
383
384         } else if (t->realtime_event_source) {
385                 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
386
387                 if (r < 0)
388                         goto fail;
389         }
390
391         timer_set_state(t, TIMER_WAITING);
392         return;
393
394 fail:
395         log_warning_unit(UNIT(t)->id,
396                          "%s failed to enter waiting state: %s",
397                          UNIT(t)->id, strerror(-r));
398         timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
399 }
400
401 static void timer_enter_running(Timer *t) {
402         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
403         int r;
404
405         assert(t);
406
407         /* Don't start job if we are supposed to go down */
408         if (unit_stop_pending(UNIT(t)))
409                 return;
410
411         r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
412                             JOB_REPLACE, true, &error, NULL);
413         if (r < 0)
414                 goto fail;
415
416         t->last_trigger_monotonic = now(CLOCK_MONOTONIC);
417
418         timer_set_state(t, TIMER_RUNNING);
419         return;
420
421 fail:
422         log_warning_unit(UNIT(t)->id,
423                          "%s failed to queue unit startup job: %s",
424                          UNIT(t)->id, bus_error_message(&error, r));
425         timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
426 }
427
428 static int timer_start(Unit *u) {
429         Timer *t = TIMER(u);
430
431         assert(t);
432         assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
433
434         if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
435                 return -ENOENT;
436
437         t->result = TIMER_SUCCESS;
438         timer_enter_waiting(t, true);
439         return 0;
440 }
441
442 static int timer_stop(Unit *u) {
443         Timer *t = TIMER(u);
444
445         assert(t);
446         assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
447
448         timer_enter_dead(t, TIMER_SUCCESS);
449         return 0;
450 }
451
452 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
453         Timer *t = TIMER(u);
454
455         assert(u);
456         assert(f);
457         assert(fds);
458
459         unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
460         unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
461
462         return 0;
463 }
464
465 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
466         Timer *t = TIMER(u);
467
468         assert(u);
469         assert(key);
470         assert(value);
471         assert(fds);
472
473         if (streq(key, "state")) {
474                 TimerState state;
475
476                 state = timer_state_from_string(value);
477                 if (state < 0)
478                         log_debug_unit(u->id, "Failed to parse state value %s", value);
479                 else
480                         t->deserialized_state = state;
481         } else if (streq(key, "result")) {
482                 TimerResult f;
483
484                 f = timer_result_from_string(value);
485                 if (f < 0)
486                         log_debug_unit(u->id, "Failed to parse result value %s", value);
487                 else if (f != TIMER_SUCCESS)
488                         t->result = f;
489
490         } else
491                 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
492
493         return 0;
494 }
495
496 _pure_ static UnitActiveState timer_active_state(Unit *u) {
497         assert(u);
498
499         return state_translation_table[TIMER(u)->state];
500 }
501
502 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
503         assert(u);
504
505         return timer_state_to_string(TIMER(u)->state);
506 }
507
508 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
509         Timer *t = TIMER(userdata);
510
511         assert(t);
512
513         if (t->state != TIMER_WAITING)
514                 return 0;
515
516         log_debug_unit(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
517         timer_enter_running(t);
518         return 0;
519 }
520
521 static void timer_trigger_notify(Unit *u, Unit *other) {
522         Timer *t = TIMER(u);
523         TimerValue *v;
524
525         assert(u);
526         assert(other);
527
528         if (other->load_state != UNIT_LOADED)
529                 return;
530
531         /* Reenable all timers that depend on unit state */
532         LIST_FOREACH(value, v, t->values)
533                 if (v->base == TIMER_UNIT_ACTIVE ||
534                     v->base == TIMER_UNIT_INACTIVE)
535                         v->disabled = false;
536
537         switch (t->state) {
538
539         case TIMER_WAITING:
540         case TIMER_ELAPSED:
541
542                 /* Recalculate sleep time */
543                 timer_enter_waiting(t, false);
544                 break;
545
546         case TIMER_RUNNING:
547
548                 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
549                         log_debug_unit(UNIT(t)->id,
550                                        "%s got notified about unit deactivation.",
551                                        UNIT(t)->id);
552                         timer_enter_waiting(t, false);
553                 }
554                 break;
555
556         case TIMER_DEAD:
557         case TIMER_FAILED:
558                 break;
559
560         default:
561                 assert_not_reached("Unknown timer state");
562         }
563 }
564
565 static void timer_reset_failed(Unit *u) {
566         Timer *t = TIMER(u);
567
568         assert(t);
569
570         if (t->state == TIMER_FAILED)
571                 timer_set_state(t, TIMER_DEAD);
572
573         t->result = TIMER_SUCCESS;
574 }
575
576 static void timer_time_change(Unit *u) {
577         Timer *t = TIMER(u);
578
579         assert(u);
580
581         if (t->state != TIMER_WAITING)
582                 return;
583
584         log_debug_unit(u->id,
585                        "%s: time change, recalculating next elapse.", u->id);
586         timer_enter_waiting(t, false);
587 }
588
589 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
590         [TIMER_DEAD] = "dead",
591         [TIMER_WAITING] = "waiting",
592         [TIMER_RUNNING] = "running",
593         [TIMER_ELAPSED] = "elapsed",
594         [TIMER_FAILED] = "failed"
595 };
596
597 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
598
599 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
600         [TIMER_ACTIVE] = "OnActiveSec",
601         [TIMER_BOOT] = "OnBootSec",
602         [TIMER_STARTUP] = "OnStartupSec",
603         [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
604         [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
605         [TIMER_CALENDAR] = "OnCalendar"
606 };
607
608 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
609
610 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
611         [TIMER_SUCCESS] = "success",
612         [TIMER_FAILURE_RESOURCES] = "resources"
613 };
614
615 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
616
617 const UnitVTable timer_vtable = {
618         .object_size = sizeof(Timer),
619
620         .sections =
621                 "Unit\0"
622                 "Timer\0"
623                 "Install\0",
624
625         .init = timer_init,
626         .done = timer_done,
627         .load = timer_load,
628
629         .coldplug = timer_coldplug,
630
631         .dump = timer_dump,
632
633         .start = timer_start,
634         .stop = timer_stop,
635
636         .serialize = timer_serialize,
637         .deserialize_item = timer_deserialize_item,
638
639         .active_state = timer_active_state,
640         .sub_state_to_string = timer_sub_state_to_string,
641
642         .trigger_notify = timer_trigger_notify,
643
644         .reset_failed = timer_reset_failed,
645         .time_change = timer_time_change,
646
647         .bus_interface = "org.freedesktop.systemd1.Timer",
648         .bus_vtable = bus_timer_vtable,
649 };