]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/timer.c
core: rename SystemdRunningAs to ManagerRunningAs
[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-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_or_boottime = USEC_INFINITY;
49 t->next_elapse_realtime = USEC_INFINITY;
50 t->accuracy_usec = u->manager->default_timer_accuracy_usec;
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 free(t->stamp_path);
79 }
80
81 static int timer_verify(Timer *t) {
82 assert(t);
83
84 if (UNIT(t)->load_state != UNIT_LOADED)
85 return 0;
86
87 if (!t->values) {
88 log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
89 return -EINVAL;
90 }
91
92 return 0;
93 }
94
95 static int timer_add_default_dependencies(Timer *t) {
96 int r;
97 TimerValue *v;
98
99 assert(t);
100
101 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
102 if (r < 0)
103 return r;
104
105 if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
106 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
107 if (r < 0)
108 return r;
109
110 LIST_FOREACH(value, v, t->values) {
111 if (v->base == TIMER_CALENDAR) {
112 r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true);
113 if (r < 0)
114 return r;
115 break;
116 }
117 }
118 }
119
120 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
121 }
122
123 static int timer_setup_persistent(Timer *t) {
124 int r;
125
126 assert(t);
127
128 if (!t->persistent)
129 return 0;
130
131 if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
132
133 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
134 if (r < 0)
135 return r;
136
137 t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
138 } else {
139 const char *e;
140
141 e = getenv("XDG_DATA_HOME");
142 if (e)
143 t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id, NULL);
144 else {
145
146 _cleanup_free_ char *h = NULL;
147
148 r = get_home_dir(&h);
149 if (r < 0)
150 return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m");
151
152 t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id, NULL);
153 }
154 }
155
156 if (!t->stamp_path)
157 return log_oom();
158
159 return 0;
160 }
161
162 static int timer_load(Unit *u) {
163 Timer *t = TIMER(u);
164 int r;
165
166 assert(u);
167 assert(u->load_state == UNIT_STUB);
168
169 r = unit_load_fragment_and_dropin(u);
170 if (r < 0)
171 return r;
172
173 if (u->load_state == UNIT_LOADED) {
174
175 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
176 Unit *x;
177
178 r = unit_load_related_unit(u, ".service", &x);
179 if (r < 0)
180 return r;
181
182 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
183 if (r < 0)
184 return r;
185 }
186
187 r = timer_setup_persistent(t);
188 if (r < 0)
189 return r;
190
191 if (u->default_dependencies) {
192 r = timer_add_default_dependencies(t);
193 if (r < 0)
194 return r;
195 }
196 }
197
198 return timer_verify(t);
199 }
200
201 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
202 char buf[FORMAT_TIMESPAN_MAX];
203 Timer *t = TIMER(u);
204 Unit *trigger;
205 TimerValue *v;
206
207 trigger = UNIT_TRIGGER(u);
208
209 fprintf(f,
210 "%sTimer State: %s\n"
211 "%sResult: %s\n"
212 "%sUnit: %s\n"
213 "%sPersistent: %s\n"
214 "%sWakeSystem: %s\n"
215 "%sAccuracy: %s\n",
216 prefix, timer_state_to_string(t->state),
217 prefix, timer_result_to_string(t->result),
218 prefix, trigger ? trigger->id : "n/a",
219 prefix, yes_no(t->persistent),
220 prefix, yes_no(t->wake_system),
221 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
222
223 LIST_FOREACH(value, v, t->values) {
224
225 if (v->base == TIMER_CALENDAR) {
226 _cleanup_free_ char *p = NULL;
227
228 calendar_spec_to_string(v->calendar_spec, &p);
229
230 fprintf(f,
231 "%s%s: %s\n",
232 prefix,
233 timer_base_to_string(v->base),
234 strna(p));
235 } else {
236 char timespan1[FORMAT_TIMESPAN_MAX];
237
238 fprintf(f,
239 "%s%s: %s\n",
240 prefix,
241 timer_base_to_string(v->base),
242 format_timespan(timespan1, sizeof(timespan1), v->value, 0));
243 }
244 }
245 }
246
247 static void timer_set_state(Timer *t, TimerState state) {
248 TimerState old_state;
249 assert(t);
250
251 old_state = t->state;
252 t->state = state;
253
254 if (state != TIMER_WAITING) {
255 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
256 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
257 }
258
259 if (state != old_state)
260 log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
261
262 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
263 }
264
265 static void timer_enter_waiting(Timer *t, bool initial);
266
267 static int timer_coldplug(Unit *u) {
268 Timer *t = TIMER(u);
269
270 assert(t);
271 assert(t->state == TIMER_DEAD);
272
273 if (t->deserialized_state != t->state) {
274
275 if (t->deserialized_state == TIMER_WAITING)
276 timer_enter_waiting(t, false);
277 else
278 timer_set_state(t, t->deserialized_state);
279 }
280
281 return 0;
282 }
283
284 static void timer_enter_dead(Timer *t, TimerResult f) {
285 assert(t);
286
287 if (f != TIMER_SUCCESS)
288 t->result = f;
289
290 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
291 }
292
293 static usec_t monotonic_to_boottime(usec_t t) {
294 usec_t a, b;
295
296 if (t <= 0)
297 return 0;
298
299 a = now(CLOCK_BOOTTIME);
300 b = now(CLOCK_MONOTONIC);
301
302 if (t + a > b)
303 return t + a - b;
304 else
305 return 0;
306 }
307
308 static void timer_enter_waiting(Timer *t, bool initial) {
309 bool found_monotonic = false, found_realtime = false;
310 usec_t ts_realtime, ts_monotonic;
311 usec_t base = 0;
312 TimerValue *v;
313 int r;
314
315 /* If we shall wake the system we use the boottime clock
316 * rather than the monotonic clock. */
317
318 ts_realtime = now(CLOCK_REALTIME);
319 ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
320 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
321
322 LIST_FOREACH(value, v, t->values) {
323
324 if (v->disabled)
325 continue;
326
327 if (v->base == TIMER_CALENDAR) {
328 usec_t b;
329
330 /* If we know the last time this was
331 * triggered, schedule the job based relative
332 * to that. If we don't just start from
333 * now. */
334
335 b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts_realtime;
336
337 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
338 if (r < 0)
339 continue;
340
341 if (!found_realtime)
342 t->next_elapse_realtime = v->next_elapse;
343 else
344 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
345
346 found_realtime = true;
347
348 } else {
349 switch (v->base) {
350
351 case TIMER_ACTIVE:
352 if (state_translation_table[t->state] == UNIT_ACTIVE)
353 base = UNIT(t)->inactive_exit_timestamp.monotonic;
354 else
355 base = ts_monotonic;
356 break;
357
358 case TIMER_BOOT:
359 /* CLOCK_MONOTONIC equals the uptime on Linux */
360 base = 0;
361 break;
362
363 case TIMER_STARTUP:
364 base = UNIT(t)->manager->userspace_timestamp.monotonic;
365 break;
366
367 case TIMER_UNIT_ACTIVE:
368
369 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
370
371 if (base <= 0)
372 base = t->last_trigger.monotonic;
373
374 if (base <= 0)
375 continue;
376
377 break;
378
379 case TIMER_UNIT_INACTIVE:
380
381 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
382
383 if (base <= 0)
384 base = t->last_trigger.monotonic;
385
386 if (base <= 0)
387 continue;
388
389 break;
390
391 default:
392 assert_not_reached("Unknown timer base");
393 }
394
395 if (t->wake_system)
396 base = monotonic_to_boottime(base);
397
398 v->next_elapse = base + v->value;
399
400 if (!initial && v->next_elapse < ts_monotonic && IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
401 /* This is a one time trigger, disable it now */
402 v->disabled = true;
403 continue;
404 }
405
406 if (!found_monotonic)
407 t->next_elapse_monotonic_or_boottime = v->next_elapse;
408 else
409 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
410
411 found_monotonic = true;
412 }
413 }
414
415 if (!found_monotonic && !found_realtime) {
416 log_unit_debug(UNIT(t), "Timer is elapsed.");
417 timer_set_state(t, TIMER_ELAPSED);
418 return;
419 }
420
421 if (found_monotonic) {
422 char buf[FORMAT_TIMESPAN_MAX];
423
424 log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
425
426 if (t->monotonic_event_source) {
427 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
428 if (r < 0)
429 goto fail;
430
431 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
432 } else
433 r = sd_event_add_time(
434 UNIT(t)->manager->event,
435 &t->monotonic_event_source,
436 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
437 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
438 timer_dispatch, t);
439 if (r < 0)
440 goto fail;
441
442 (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
443
444 } else if (t->monotonic_event_source) {
445
446 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
447 if (r < 0)
448 goto fail;
449 }
450
451 if (found_realtime) {
452 char buf[FORMAT_TIMESTAMP_MAX];
453 log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
454
455 if (t->realtime_event_source) {
456 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
457 if (r < 0)
458 goto fail;
459
460 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
461 } else
462 r = sd_event_add_time(
463 UNIT(t)->manager->event,
464 &t->realtime_event_source,
465 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
466 t->next_elapse_realtime, t->accuracy_usec,
467 timer_dispatch, t);
468 if (r < 0)
469 goto fail;
470
471 (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
472
473 } else if (t->realtime_event_source) {
474
475 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
476 if (r < 0)
477 goto fail;
478 }
479
480 timer_set_state(t, TIMER_WAITING);
481 return;
482
483 fail:
484 log_unit_warning_errno(UNIT(t), r, "Failed to enter waiting state: %m");
485 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
486 }
487
488 static void timer_enter_running(Timer *t) {
489 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
490 int r;
491
492 assert(t);
493
494 /* Don't start job if we are supposed to go down */
495 if (unit_stop_pending(UNIT(t)))
496 return;
497
498 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
499 JOB_REPLACE, true, &error, NULL);
500 if (r < 0)
501 goto fail;
502
503 dual_timestamp_get(&t->last_trigger);
504
505 if (t->stamp_path)
506 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0);
507
508 timer_set_state(t, TIMER_RUNNING);
509 return;
510
511 fail:
512 log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
513 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
514 }
515
516 static int timer_start(Unit *u) {
517 Timer *t = TIMER(u);
518 TimerValue *v;
519
520 assert(t);
521 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
522
523 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
524 return -ENOENT;
525
526 t->last_trigger = DUAL_TIMESTAMP_NULL;
527
528 /* Reenable all timers that depend on unit activation time */
529 LIST_FOREACH(value, v, t->values)
530 if (v->base == TIMER_ACTIVE)
531 v->disabled = false;
532
533 if (t->stamp_path) {
534 struct stat st;
535
536 if (stat(t->stamp_path, &st) >= 0)
537 t->last_trigger.realtime = timespec_load(&st.st_atim);
538 else if (errno == ENOENT)
539 /* The timer has never run before,
540 * make sure a stamp file exists.
541 */
542 touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
543 }
544
545 t->result = TIMER_SUCCESS;
546 timer_enter_waiting(t, true);
547 return 1;
548 }
549
550 static int timer_stop(Unit *u) {
551 Timer *t = TIMER(u);
552
553 assert(t);
554 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
555
556 timer_enter_dead(t, TIMER_SUCCESS);
557 return 1;
558 }
559
560 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
561 Timer *t = TIMER(u);
562
563 assert(u);
564 assert(f);
565 assert(fds);
566
567 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
568 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
569
570 if (t->last_trigger.realtime > 0)
571 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
572
573 if (t->last_trigger.monotonic > 0)
574 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
575
576 return 0;
577 }
578
579 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
580 Timer *t = TIMER(u);
581 int r;
582
583 assert(u);
584 assert(key);
585 assert(value);
586 assert(fds);
587
588 if (streq(key, "state")) {
589 TimerState state;
590
591 state = timer_state_from_string(value);
592 if (state < 0)
593 log_unit_debug(u, "Failed to parse state value: %s", value);
594 else
595 t->deserialized_state = state;
596 } else if (streq(key, "result")) {
597 TimerResult f;
598
599 f = timer_result_from_string(value);
600 if (f < 0)
601 log_unit_debug(u, "Failed to parse result value: %s", value);
602 else if (f != TIMER_SUCCESS)
603 t->result = f;
604 } else if (streq(key, "last-trigger-realtime")) {
605
606 r = safe_atou64(value, &t->last_trigger.realtime);
607 if (r < 0)
608 log_unit_debug(u, "Failed to parse last-trigger-realtime value: %s", value);
609
610 } else if (streq(key, "last-trigger-monotonic")) {
611
612 r = safe_atou64(value, &t->last_trigger.monotonic);
613 if (r < 0)
614 log_unit_debug(u, "Failed to parse last-trigger-monotonic value: %s", value);
615
616 } else
617 log_unit_debug(u, "Unknown serialization key: %s", key);
618
619 return 0;
620 }
621
622 _pure_ static UnitActiveState timer_active_state(Unit *u) {
623 assert(u);
624
625 return state_translation_table[TIMER(u)->state];
626 }
627
628 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
629 assert(u);
630
631 return timer_state_to_string(TIMER(u)->state);
632 }
633
634 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
635 Timer *t = TIMER(userdata);
636
637 assert(t);
638
639 if (t->state != TIMER_WAITING)
640 return 0;
641
642 log_unit_debug(UNIT(t), "Timer elapsed.");
643 timer_enter_running(t);
644 return 0;
645 }
646
647 static void timer_trigger_notify(Unit *u, Unit *other) {
648 Timer *t = TIMER(u);
649 TimerValue *v;
650
651 assert(u);
652 assert(other);
653
654 if (other->load_state != UNIT_LOADED)
655 return;
656
657 /* Reenable all timers that depend on unit state */
658 LIST_FOREACH(value, v, t->values)
659 if (v->base == TIMER_UNIT_ACTIVE ||
660 v->base == TIMER_UNIT_INACTIVE)
661 v->disabled = false;
662
663 switch (t->state) {
664
665 case TIMER_WAITING:
666 case TIMER_ELAPSED:
667
668 /* Recalculate sleep time */
669 timer_enter_waiting(t, false);
670 break;
671
672 case TIMER_RUNNING:
673
674 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
675 log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
676 timer_enter_waiting(t, false);
677 }
678 break;
679
680 case TIMER_DEAD:
681 case TIMER_FAILED:
682 break;
683
684 default:
685 assert_not_reached("Unknown timer state");
686 }
687 }
688
689 static void timer_reset_failed(Unit *u) {
690 Timer *t = TIMER(u);
691
692 assert(t);
693
694 if (t->state == TIMER_FAILED)
695 timer_set_state(t, TIMER_DEAD);
696
697 t->result = TIMER_SUCCESS;
698 }
699
700 static void timer_time_change(Unit *u) {
701 Timer *t = TIMER(u);
702
703 assert(u);
704
705 if (t->state != TIMER_WAITING)
706 return;
707
708 log_unit_debug(u, "Time change, recalculating next elapse.");
709 timer_enter_waiting(t, false);
710 }
711
712 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
713 [TIMER_DEAD] = "dead",
714 [TIMER_WAITING] = "waiting",
715 [TIMER_RUNNING] = "running",
716 [TIMER_ELAPSED] = "elapsed",
717 [TIMER_FAILED] = "failed"
718 };
719
720 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
721
722 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
723 [TIMER_ACTIVE] = "OnActiveSec",
724 [TIMER_BOOT] = "OnBootSec",
725 [TIMER_STARTUP] = "OnStartupSec",
726 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
727 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
728 [TIMER_CALENDAR] = "OnCalendar"
729 };
730
731 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
732
733 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
734 [TIMER_SUCCESS] = "success",
735 [TIMER_FAILURE_RESOURCES] = "resources"
736 };
737
738 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
739
740 const UnitVTable timer_vtable = {
741 .object_size = sizeof(Timer),
742
743 .sections =
744 "Unit\0"
745 "Timer\0"
746 "Install\0",
747 .private_section = "Timer",
748
749 .init = timer_init,
750 .done = timer_done,
751 .load = timer_load,
752
753 .coldplug = timer_coldplug,
754
755 .dump = timer_dump,
756
757 .start = timer_start,
758 .stop = timer_stop,
759
760 .serialize = timer_serialize,
761 .deserialize_item = timer_deserialize_item,
762
763 .active_state = timer_active_state,
764 .sub_state_to_string = timer_sub_state_to_string,
765
766 .trigger_notify = timer_trigger_notify,
767
768 .reset_failed = timer_reset_failed,
769 .time_change = timer_time_change,
770
771 .bus_interface = "org.freedesktop.systemd1.Timer",
772 .bus_vtable = bus_timer_vtable,
773 .bus_set_property = bus_timer_set_property,
774
775 .can_transient = true,
776 };