Coverage Report

Created: 2019-06-19 13:33

/src/systemd/src/core/dbus-timer.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1+ */
2
3
#include "alloc-util.h"
4
#include "bus-util.h"
5
#include "dbus-timer.h"
6
#include "dbus-util.h"
7
#include "strv.h"
8
#include "timer.h"
9
#include "unit.h"
10
11
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
12
13
static int property_get_monotonic_timers(
14
                sd_bus *bus,
15
                const char *path,
16
                const char *interface,
17
                const char *property,
18
                sd_bus_message *reply,
19
                void *userdata,
20
0
                sd_bus_error *error) {
21
0
22
0
        Timer *t = userdata;
23
0
        TimerValue *v;
24
0
        int r;
25
0
26
0
        assert(bus);
27
0
        assert(reply);
28
0
        assert(t);
29
0
30
0
        r = sd_bus_message_open_container(reply, 'a', "(stt)");
31
0
        if (r < 0)
32
0
                return r;
33
0
34
0
        LIST_FOREACH(value, v, t->values) {
35
0
                _cleanup_free_ char *buf = NULL;
36
0
                const char *s;
37
0
                size_t l;
38
0
39
0
                if (v->base == TIMER_CALENDAR)
40
0
                        continue;
41
0
42
0
                s = timer_base_to_string(v->base);
43
0
                assert(endswith(s, "Sec"));
44
0
45
0
                /* s/Sec/USec/ */
46
0
                l = strlen(s);
47
0
                buf = new(char, l+2);
48
0
                if (!buf)
49
0
                        return -ENOMEM;
50
0
51
0
                memcpy(buf, s, l-3);
52
0
                memcpy(buf+l-3, "USec", 5);
53
0
54
0
                r = sd_bus_message_append(reply, "(stt)", buf, v->value, v->next_elapse);
55
0
                if (r < 0)
56
0
                        return r;
57
0
        }
58
0
59
0
        return sd_bus_message_close_container(reply);
60
0
}
61
62
static int property_get_calendar_timers(
63
                sd_bus *bus,
64
                const char *path,
65
                const char *interface,
66
                const char *property,
67
                sd_bus_message *reply,
68
                void *userdata,
69
0
                sd_bus_error *error) {
70
0
71
0
        Timer *t = userdata;
72
0
        TimerValue *v;
73
0
        int r;
74
0
75
0
        assert(bus);
76
0
        assert(reply);
77
0
        assert(t);
78
0
79
0
        r = sd_bus_message_open_container(reply, 'a', "(sst)");
80
0
        if (r < 0)
81
0
                return r;
82
0
83
0
        LIST_FOREACH(value, v, t->values) {
84
0
                _cleanup_free_ char *buf = NULL;
85
0
86
0
                if (v->base != TIMER_CALENDAR)
87
0
                        continue;
88
0
89
0
                r = calendar_spec_to_string(v->calendar_spec, &buf);
90
0
                if (r < 0)
91
0
                        return r;
92
0
93
0
                r = sd_bus_message_append(reply, "(sst)", timer_base_to_string(v->base), buf, v->next_elapse);
94
0
                if (r < 0)
95
0
                        return r;
96
0
        }
97
0
98
0
        return sd_bus_message_close_container(reply);
99
0
}
100
101
static int property_get_next_elapse_monotonic(
102
                sd_bus *bus,
103
                const char *path,
104
                const char *interface,
105
                const char *property,
106
                sd_bus_message *reply,
107
                void *userdata,
108
0
                sd_bus_error *error) {
109
0
110
0
        Timer *t = userdata;
111
0
112
0
        assert(bus);
113
0
        assert(reply);
114
0
        assert(t);
115
0
116
0
        return sd_bus_message_append(reply, "t",
117
0
                                     (uint64_t) usec_shift_clock(t->next_elapse_monotonic_or_boottime,
118
0
                                                                 TIMER_MONOTONIC_CLOCK(t), CLOCK_MONOTONIC));
119
0
}
120
121
const sd_bus_vtable bus_timer_vtable[] = {
122
        SD_BUS_VTABLE_START(0),
123
        SD_BUS_PROPERTY("Unit", "s", bus_property_get_triggered_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
124
        SD_BUS_PROPERTY("TimersMonotonic", "a(stt)", property_get_monotonic_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
125
        SD_BUS_PROPERTY("TimersCalendar", "a(sst)", property_get_calendar_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
126
        SD_BUS_PROPERTY("OnClockChange", "b", bus_property_get_bool, offsetof(Timer, on_clock_change), SD_BUS_VTABLE_PROPERTY_CONST),
127
        SD_BUS_PROPERTY("OnTimezoneChange", "b", bus_property_get_bool, offsetof(Timer, on_timezone_change), SD_BUS_VTABLE_PROPERTY_CONST),
128
        SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
129
        SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", property_get_next_elapse_monotonic, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
130
        BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
131
        SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
132
        SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
133
        SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
134
        SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
135
        SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
136
        SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST),
137
        SD_BUS_VTABLE_END
138
};
139
140
static int bus_timer_set_transient_property(
141
                Timer *t,
142
                const char *name,
143
                sd_bus_message *message,
144
                UnitWriteFlags flags,
145
                sd_bus_error *error) {
146
147
        Unit *u = UNIT(t);
148
        int r;
149
150
        assert(t);
151
        assert(name);
152
        assert(message);
153
154
        flags |= UNIT_PRIVATE;
155
156
        if (streq(name, "AccuracyUSec"))
157
                return bus_set_transient_usec(u, name, &t->accuracy_usec, message, flags, error);
158
159
        if (streq(name, "AccuracySec")) {
160
                log_notice("Client is using obsolete AccuracySec= transient property, please use AccuracyUSec= instead.");
161
                return bus_set_transient_usec(u, "AccuracyUSec", &t->accuracy_usec, message, flags, error);
162
        }
163
164
        if (streq(name, "RandomizedDelayUSec"))
165
                return bus_set_transient_usec(u, name, &t->random_usec, message, flags, error);
166
167
        if (streq(name, "WakeSystem"))
168
                return bus_set_transient_bool(u, name, &t->wake_system, message, flags, error);
169
170
        if (streq(name, "Persistent"))
171
                return bus_set_transient_bool(u, name, &t->persistent, message, flags, error);
172
173
        if (streq(name, "RemainAfterElapse"))
174
                return bus_set_transient_bool(u, name, &t->remain_after_elapse, message, flags, error);
175
176
        if (streq(name, "OnTimezoneChange"))
177
                return bus_set_transient_bool(u, name, &t->on_timezone_change, message, flags, error);
178
179
        if (streq(name, "OnClockChange"))
180
                return bus_set_transient_bool(u, name, &t->on_clock_change, message, flags, error);
181
182
        if (streq(name, "TimersMonotonic")) {
183
                const char *base_name;
184
                usec_t usec = 0;
185
                bool empty = true;
186
187
                r = sd_bus_message_enter_container(message, 'a', "(st)");
188
                if (r < 0)
189
                        return r;
190
191
                while ((r = sd_bus_message_read(message, "(st)", &base_name, &usec)) > 0) {
192
                        TimerBase b;
193
194
                        b = timer_base_from_string(base_name);
195
                        if (b < 0 || b == TIMER_CALENDAR)
196
                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid timer base: %s", base_name);
197
198
                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
199
                                char ts[FORMAT_TIMESPAN_MAX];
200
                                TimerValue *v;
201
202
                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", base_name,
203
                                                    format_timespan(ts, sizeof(ts), usec, USEC_PER_MSEC));
204
205
                                v = new(TimerValue, 1);
206
                                if (!v)
207
                                        return -ENOMEM;
208
209
                                *v = (TimerValue) {
210
                                        .base = b,
211
                                        .value = usec,
212
                                };
213
214
                                LIST_PREPEND(value, t->values, v);
215
                        }
216
217
                        empty = false;
218
                }
219
                if (r < 0)
220
                        return r;
221
222
                r = sd_bus_message_exit_container(message);
223
                if (r < 0)
224
                        return r;
225
226
                if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
227
                        timer_free_values(t);
228
                        unit_write_setting(u, flags, name, "OnActiveSec=");
229
                }
230
231
                return 1;
232
233
        } else if (streq(name, "TimersCalendar")) {
234
                const char *base_name, *str;
235
                bool empty = true;
236
237
                r = sd_bus_message_enter_container(message, 'a', "(ss)");
238
                if (r < 0)
239
                        return r;
240
241
                while ((r = sd_bus_message_read(message, "(ss)", &base_name, &str)) > 0) {
242
                        _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
243
                        TimerBase b;
244
245
                        b = timer_base_from_string(base_name);
246
                        if (b != TIMER_CALENDAR)
247
                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid timer base: %s", base_name);
248
249
                        r = calendar_spec_from_string(str, &c);
250
                        if (r == -EINVAL)
251
                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid calendar spec: %s", str);
252
                        if (r < 0)
253
                                return r;
254
255
                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
256
                                TimerValue *v;
257
258
                                unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", base_name, str);
259
260
                                v = new(TimerValue, 1);
261
                                if (!v)
262
                                        return -ENOMEM;
263
264
                                *v = (TimerValue) {
265
                                        .base = b,
266
                                        .calendar_spec = TAKE_PTR(c),
267
                                };
268
269
                                LIST_PREPEND(value, t->values, v);
270
                        }
271
272
                        empty = false;
273
                }
274
                if (r < 0)
275
                        return r;
276
277
                r = sd_bus_message_exit_container(message);
278
                if (r < 0)
279
                        return r;
280
281
                if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
282
                        timer_free_values(t);
283
                        unit_write_setting(u, flags, name, "OnCalendar=");
284
                }
285
286
                return 1;
287
288
        } else if (STR_IN_SET(name,
289
                       "OnActiveSec",
290
                       "OnBootSec",
291
                       "OnStartupSec",
292
                       "OnUnitActiveSec",
293
                       "OnUnitInactiveSec")) {
294
295
                TimerValue *v;
296
                TimerBase b = _TIMER_BASE_INVALID;
297
                usec_t usec = 0;
298
299
                log_notice("Client is using obsolete %s= transient property, please use TimersMonotonic= instead.", name);
300
301
                b = timer_base_from_string(name);
302
                if (b < 0)
303
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown timer base");
304
305
                r = sd_bus_message_read(message, "t", &usec);
306
                if (r < 0)
307
                        return r;
308
309
                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
310
                        char time[FORMAT_TIMESPAN_MAX];
311
312
                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name,
313
                                            format_timespan(time, sizeof(time), usec, USEC_PER_MSEC));
314
315
                        v = new(TimerValue, 1);
316
                        if (!v)
317
                                return -ENOMEM;
318
319
                        *v = (TimerValue) {
320
                                .base = b,
321
                                .value = usec,
322
                        };
323
324
                        LIST_PREPEND(value, t->values, v);
325
                }
326
327
                return 1;
328
329
        } else if (streq(name, "OnCalendar")) {
330
331
                TimerValue *v;
332
                _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
333
                const char *str;
334
335
                log_notice("Client is using obsolete %s= transient property, please use TimersCalendar= instead.", name);
336
337
                r = sd_bus_message_read(message, "s", &str);
338
                if (r < 0)
339
                        return r;
340
341
                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
342
                        r = calendar_spec_from_string(str, &c);
343
                        if (r == -EINVAL)
344
                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid calendar spec");
345
                        if (r < 0)
346
                                return r;
347
348
                        unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, str);
349
350
                        v = new(TimerValue, 1);
351
                        if (!v)
352
                                return -ENOMEM;
353
354
                        *v = (TimerValue) {
355
                                .base = TIMER_CALENDAR,
356
                                .calendar_spec = TAKE_PTR(c),
357
                        };
358
359
                        LIST_PREPEND(value, t->values, v);
360
                }
361
362
                return 1;
363
        }
364
365
        return 0;
366
}
367
368
int bus_timer_set_property(
369
                Unit *u,
370
                const char *name,
371
                sd_bus_message *message,
372
                UnitWriteFlags mode,
373
0
                sd_bus_error *error) {
374
0
375
0
        Timer *t = TIMER(u);
376
0
377
0
        assert(t);
378
0
        assert(name);
379
0
        assert(message);
380
0
381
0
        if (u->transient && u->load_state == UNIT_STUB)
382
0
                return bus_timer_set_transient_property(t, name, message, mode, error);
383
0
384
0
        return 0;
385
0
}