chiark / gitweb /
util: add a bit of syntactic sugar to run short code fragments with a different umask
[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-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         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 (!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, 0)));
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, 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_debug_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 };