]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/timer.c
remove unused includes
[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)->id, "%s lacks value setting. Refusing.", UNIT(t)->id);
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 == SYSTEMD_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 == SYSTEMD_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_error_errno(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)->id,
261 "%s changed %s -> %s", UNIT(t)->id,
262 timer_state_to_string(old_state),
263 timer_state_to_string(state));
264
265 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
266 }
267
268 static void timer_enter_waiting(Timer *t, bool initial);
269
270 static int timer_coldplug(Unit *u) {
271 Timer *t = TIMER(u);
272
273 assert(t);
274 assert(t->state == TIMER_DEAD);
275
276 if (t->deserialized_state != t->state) {
277
278 if (t->deserialized_state == TIMER_WAITING)
279 timer_enter_waiting(t, false);
280 else
281 timer_set_state(t, t->deserialized_state);
282 }
283
284 return 0;
285 }
286
287 static void timer_enter_dead(Timer *t, TimerResult f) {
288 assert(t);
289
290 if (f != TIMER_SUCCESS)
291 t->result = f;
292
293 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
294 }
295
296 static usec_t monotonic_to_boottime(usec_t t) {
297 usec_t a, b;
298
299 if (t <= 0)
300 return 0;
301
302 a = now(CLOCK_BOOTTIME);
303 b = now(CLOCK_MONOTONIC);
304
305 if (t + a > b)
306 return t + a - b;
307 else
308 return 0;
309 }
310
311 static void timer_enter_waiting(Timer *t, bool initial) {
312 bool found_monotonic = false, found_realtime = false;
313 usec_t ts_realtime, ts_monotonic;
314 usec_t base = 0;
315 TimerValue *v;
316 int r;
317
318 /* If we shall wake the system we use the boottime clock
319 * rather than the monotonic clock. */
320
321 ts_realtime = now(CLOCK_REALTIME);
322 ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
323 t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
324
325 LIST_FOREACH(value, v, t->values) {
326
327 if (v->disabled)
328 continue;
329
330 if (v->base == TIMER_CALENDAR) {
331 usec_t b;
332
333 /* If we know the last time this was
334 * triggered, schedule the job based relative
335 * to that. If we don't just start from
336 * now. */
337
338 b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts_realtime;
339
340 r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
341 if (r < 0)
342 continue;
343
344 if (!found_realtime)
345 t->next_elapse_realtime = v->next_elapse;
346 else
347 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
348
349 found_realtime = true;
350
351 } else {
352 switch (v->base) {
353
354 case TIMER_ACTIVE:
355 if (state_translation_table[t->state] == UNIT_ACTIVE)
356 base = UNIT(t)->inactive_exit_timestamp.monotonic;
357 else
358 base = ts_monotonic;
359 break;
360
361 case TIMER_BOOT:
362 /* CLOCK_MONOTONIC equals the uptime on Linux */
363 base = 0;
364 break;
365
366 case TIMER_STARTUP:
367 base = UNIT(t)->manager->userspace_timestamp.monotonic;
368 break;
369
370 case TIMER_UNIT_ACTIVE:
371
372 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
373
374 if (base <= 0)
375 base = t->last_trigger.monotonic;
376
377 if (base <= 0)
378 continue;
379
380 break;
381
382 case TIMER_UNIT_INACTIVE:
383
384 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
385
386 if (base <= 0)
387 base = t->last_trigger.monotonic;
388
389 if (base <= 0)
390 continue;
391
392 break;
393
394 default:
395 assert_not_reached("Unknown timer base");
396 }
397
398 if (t->wake_system)
399 base = monotonic_to_boottime(base);
400
401 v->next_elapse = base + v->value;
402
403 if (!initial && v->next_elapse < ts_monotonic && IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
404 /* This is a one time trigger, disable it now */
405 v->disabled = true;
406 continue;
407 }
408
409 if (!found_monotonic)
410 t->next_elapse_monotonic_or_boottime = v->next_elapse;
411 else
412 t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
413
414 found_monotonic = true;
415 }
416 }
417
418 if (!found_monotonic && !found_realtime) {
419 log_unit_debug(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
420 timer_set_state(t, TIMER_ELAPSED);
421 return;
422 }
423
424 if (found_monotonic) {
425 char buf[FORMAT_TIMESPAN_MAX];
426
427 log_unit_debug(UNIT(t)->id, "%s: Monotonic timer elapses in %s.",
428 UNIT(t)->id,
429 format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
430
431 if (t->monotonic_event_source) {
432 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
433 if (r < 0)
434 goto fail;
435
436 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
437 } else
438 r = sd_event_add_time(
439 UNIT(t)->manager->event,
440 &t->monotonic_event_source,
441 t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
442 t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
443 timer_dispatch, t);
444 if (r < 0)
445 goto fail;
446
447 } else if (t->monotonic_event_source) {
448
449 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
450 if (r < 0)
451 goto fail;
452 }
453
454 if (found_realtime) {
455 char buf[FORMAT_TIMESTAMP_MAX];
456 log_unit_debug(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
457
458 if (t->realtime_event_source) {
459 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
460 if (r < 0)
461 goto fail;
462
463 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
464 } else
465 r = sd_event_add_time(
466 UNIT(t)->manager->event,
467 &t->realtime_event_source,
468 t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
469 t->next_elapse_realtime, t->accuracy_usec,
470 timer_dispatch, t);
471 if (r < 0)
472 goto fail;
473
474 } else if (t->realtime_event_source) {
475
476 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
477 if (r < 0)
478 goto fail;
479 }
480
481 timer_set_state(t, TIMER_WAITING);
482 return;
483
484 fail:
485 log_unit_warning_errno(UNIT(t)->id, r, "%s failed to enter waiting state: %m", UNIT(t)->id);
486 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
487 }
488
489 static void timer_enter_running(Timer *t) {
490 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
491 int r;
492
493 assert(t);
494
495 /* Don't start job if we are supposed to go down */
496 if (unit_stop_pending(UNIT(t)))
497 return;
498
499 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
500 JOB_REPLACE, true, &error, NULL);
501 if (r < 0)
502 goto fail;
503
504 dual_timestamp_get(&t->last_trigger);
505
506 if (t->stamp_path)
507 touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0);
508
509 timer_set_state(t, TIMER_RUNNING);
510 return;
511
512 fail:
513 log_unit_warning(UNIT(t)->id,
514 "%s failed to queue unit startup job: %s",
515 UNIT(t)->id, bus_error_message(&error, r));
516 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
517 }
518
519 static int timer_start(Unit *u) {
520 Timer *t = TIMER(u);
521 TimerValue *v;
522
523 assert(t);
524 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
525
526 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
527 return -ENOENT;
528
529 t->last_trigger = DUAL_TIMESTAMP_NULL;
530
531 /* Reenable all timers that depend on unit activation time */
532 LIST_FOREACH(value, v, t->values)
533 if (v->base == TIMER_ACTIVE)
534 v->disabled = false;
535
536 if (t->stamp_path) {
537 struct stat st;
538
539 if (stat(t->stamp_path, &st) >= 0)
540 t->last_trigger.realtime = timespec_load(&st.st_atim);
541 else if (errno == ENOENT)
542 /* The timer has never run before,
543 * make sure a stamp file exists.
544 */
545 touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
546 }
547
548 t->result = TIMER_SUCCESS;
549 timer_enter_waiting(t, true);
550 return 1;
551 }
552
553 static int timer_stop(Unit *u) {
554 Timer *t = TIMER(u);
555
556 assert(t);
557 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
558
559 timer_enter_dead(t, TIMER_SUCCESS);
560 return 1;
561 }
562
563 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
564 Timer *t = TIMER(u);
565
566 assert(u);
567 assert(f);
568 assert(fds);
569
570 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
571 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
572
573 if (t->last_trigger.realtime > 0)
574 unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
575
576 if (t->last_trigger.monotonic > 0)
577 unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
578
579 return 0;
580 }
581
582 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
583 Timer *t = TIMER(u);
584 int r;
585
586 assert(u);
587 assert(key);
588 assert(value);
589 assert(fds);
590
591 if (streq(key, "state")) {
592 TimerState state;
593
594 state = timer_state_from_string(value);
595 if (state < 0)
596 log_unit_debug(u->id, "Failed to parse state value %s", value);
597 else
598 t->deserialized_state = state;
599 } else if (streq(key, "result")) {
600 TimerResult f;
601
602 f = timer_result_from_string(value);
603 if (f < 0)
604 log_unit_debug(u->id, "Failed to parse result value %s", value);
605 else if (f != TIMER_SUCCESS)
606 t->result = f;
607 } else if (streq(key, "last-trigger-realtime")) {
608
609 r = safe_atou64(value, &t->last_trigger.realtime);
610 if (r < 0)
611 log_unit_debug(u->id, "Failed to parse last-trigger-realtime value %s", value);
612
613 } else if (streq(key, "last-trigger-monotonic")) {
614
615 r = safe_atou64(value, &t->last_trigger.monotonic);
616 if (r < 0)
617 log_unit_debug(u->id, "Failed to parse last-trigger-monotonic value %s", value);
618
619 } else
620 log_unit_debug(u->id, "Unknown serialization key '%s'", key);
621
622 return 0;
623 }
624
625 _pure_ static UnitActiveState timer_active_state(Unit *u) {
626 assert(u);
627
628 return state_translation_table[TIMER(u)->state];
629 }
630
631 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
632 assert(u);
633
634 return timer_state_to_string(TIMER(u)->state);
635 }
636
637 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
638 Timer *t = TIMER(userdata);
639
640 assert(t);
641
642 if (t->state != TIMER_WAITING)
643 return 0;
644
645 log_unit_debug(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
646 timer_enter_running(t);
647 return 0;
648 }
649
650 static void timer_trigger_notify(Unit *u, Unit *other) {
651 Timer *t = TIMER(u);
652 TimerValue *v;
653
654 assert(u);
655 assert(other);
656
657 if (other->load_state != UNIT_LOADED)
658 return;
659
660 /* Reenable all timers that depend on unit state */
661 LIST_FOREACH(value, v, t->values)
662 if (v->base == TIMER_UNIT_ACTIVE ||
663 v->base == TIMER_UNIT_INACTIVE)
664 v->disabled = false;
665
666 switch (t->state) {
667
668 case TIMER_WAITING:
669 case TIMER_ELAPSED:
670
671 /* Recalculate sleep time */
672 timer_enter_waiting(t, false);
673 break;
674
675 case TIMER_RUNNING:
676
677 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
678 log_unit_debug(UNIT(t)->id, "%s got notified about unit deactivation.", UNIT(t)->id);
679 timer_enter_waiting(t, false);
680 }
681 break;
682
683 case TIMER_DEAD:
684 case TIMER_FAILED:
685 break;
686
687 default:
688 assert_not_reached("Unknown timer state");
689 }
690 }
691
692 static void timer_reset_failed(Unit *u) {
693 Timer *t = TIMER(u);
694
695 assert(t);
696
697 if (t->state == TIMER_FAILED)
698 timer_set_state(t, TIMER_DEAD);
699
700 t->result = TIMER_SUCCESS;
701 }
702
703 static void timer_time_change(Unit *u) {
704 Timer *t = TIMER(u);
705
706 assert(u);
707
708 if (t->state != TIMER_WAITING)
709 return;
710
711 log_unit_debug(u->id, "%s: time change, recalculating next elapse.", u->id);
712 timer_enter_waiting(t, false);
713 }
714
715 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
716 [TIMER_DEAD] = "dead",
717 [TIMER_WAITING] = "waiting",
718 [TIMER_RUNNING] = "running",
719 [TIMER_ELAPSED] = "elapsed",
720 [TIMER_FAILED] = "failed"
721 };
722
723 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
724
725 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
726 [TIMER_ACTIVE] = "OnActiveSec",
727 [TIMER_BOOT] = "OnBootSec",
728 [TIMER_STARTUP] = "OnStartupSec",
729 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
730 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
731 [TIMER_CALENDAR] = "OnCalendar"
732 };
733
734 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
735
736 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
737 [TIMER_SUCCESS] = "success",
738 [TIMER_FAILURE_RESOURCES] = "resources"
739 };
740
741 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
742
743 const UnitVTable timer_vtable = {
744 .object_size = sizeof(Timer),
745
746 .sections =
747 "Unit\0"
748 "Timer\0"
749 "Install\0",
750 .private_section = "Timer",
751
752 .init = timer_init,
753 .done = timer_done,
754 .load = timer_load,
755
756 .coldplug = timer_coldplug,
757
758 .dump = timer_dump,
759
760 .start = timer_start,
761 .stop = timer_stop,
762
763 .serialize = timer_serialize,
764 .deserialize_item = timer_deserialize_item,
765
766 .active_state = timer_active_state,
767 .sub_state_to_string = timer_sub_state_to_string,
768
769 .trigger_notify = timer_trigger_notify,
770
771 .reset_failed = timer_reset_failed,
772 .time_change = timer_time_change,
773
774 .bus_interface = "org.freedesktop.systemd1.Timer",
775 .bus_vtable = bus_timer_vtable,
776 .bus_set_property = bus_timer_set_property,
777
778 .can_transient = true,
779 };