Branch data Line data Source code
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 [ # # # # : 0 : static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
# # ]
12 : :
13 : 0 : 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 : : sd_bus_error *error) {
21 : :
22 : 0 : Timer *t = userdata;
23 : : TimerValue *v;
24 : : int r;
25 : :
26 [ # # ]: 0 : assert(bus);
27 [ # # ]: 0 : assert(reply);
28 [ # # ]: 0 : assert(t);
29 : :
30 : 0 : r = sd_bus_message_open_container(reply, 'a', "(stt)");
31 [ # # ]: 0 : if (r < 0)
32 : 0 : return r;
33 : :
34 [ # # ]: 0 : LIST_FOREACH(value, v, t->values) {
35 [ # # # ]: 0 : _cleanup_free_ char *buf = NULL;
36 : : const char *s;
37 : : size_t l;
38 : :
39 [ # # ]: 0 : if (v->base == TIMER_CALENDAR)
40 : 0 : continue;
41 : :
42 : 0 : s = timer_base_to_string(v->base);
43 [ # # ]: 0 : assert(endswith(s, "Sec"));
44 : :
45 : : /* s/Sec/USec/ */
46 : 0 : l = strlen(s);
47 : 0 : buf = new(char, l+2);
48 [ # # ]: 0 : if (!buf)
49 : 0 : return -ENOMEM;
50 : :
51 : 0 : memcpy(buf, s, l-3);
52 : 0 : memcpy(buf+l-3, "USec", 5);
53 : :
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 : : }
58 : :
59 : 0 : return sd_bus_message_close_container(reply);
60 : : }
61 : :
62 : 0 : 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 : : sd_bus_error *error) {
70 : :
71 : 0 : Timer *t = userdata;
72 : : TimerValue *v;
73 : : int r;
74 : :
75 [ # # ]: 0 : assert(bus);
76 [ # # ]: 0 : assert(reply);
77 [ # # ]: 0 : assert(t);
78 : :
79 : 0 : r = sd_bus_message_open_container(reply, 'a', "(sst)");
80 [ # # ]: 0 : if (r < 0)
81 : 0 : return r;
82 : :
83 [ # # ]: 0 : LIST_FOREACH(value, v, t->values) {
84 [ # # # ]: 0 : _cleanup_free_ char *buf = NULL;
85 : :
86 [ # # ]: 0 : if (v->base != TIMER_CALENDAR)
87 : 0 : continue;
88 : :
89 : 0 : r = calendar_spec_to_string(v->calendar_spec, &buf);
90 [ # # ]: 0 : if (r < 0)
91 : 0 : return r;
92 : :
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 : : }
97 : :
98 : 0 : return sd_bus_message_close_container(reply);
99 : : }
100 : :
101 : 0 : 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 : : sd_bus_error *error) {
109 : :
110 : 0 : Timer *t = userdata;
111 : :
112 [ # # ]: 0 : assert(bus);
113 [ # # ]: 0 : assert(reply);
114 [ # # ]: 0 : assert(t);
115 : :
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 : : }
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 : 0 : static int timer_add_one_monotonic_spec(
141 : : Timer *t,
142 : : const char *name,
143 : : TimerBase base,
144 : : UnitWriteFlags flags,
145 : : usec_t usec,
146 : : sd_bus_error *error) {
147 : :
148 [ # # ]: 0 : if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
149 : : char ts[FORMAT_TIMESPAN_MAX];
150 : : TimerValue *v;
151 : :
152 [ # # ]: 0 : unit_write_settingf(UNIT(t), flags|UNIT_ESCAPE_SPECIFIERS, name,
153 : : "%s=%s",
154 : : timer_base_to_string(base),
155 : : format_timespan(ts, sizeof ts, usec, USEC_PER_MSEC));
156 : :
157 : 0 : v = new(TimerValue, 1);
158 [ # # ]: 0 : if (!v)
159 : 0 : return -ENOMEM;
160 : :
161 : 0 : *v = (TimerValue) {
162 : : .base = base,
163 : : .value = usec,
164 : : };
165 : :
166 [ # # # # ]: 0 : LIST_PREPEND(value, t->values, v);
167 : : }
168 : :
169 : 0 : return 1;
170 : : }
171 : :
172 : 0 : static int timer_add_one_calendar_spec(
173 : : Timer *t,
174 : : const char *name,
175 : : TimerBase base,
176 : : UnitWriteFlags flags,
177 : : const char *str,
178 : : sd_bus_error *error) {
179 : :
180 : 0 : _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
181 : : int r;
182 : :
183 : 0 : r = calendar_spec_from_string(str, &c);
184 [ # # ]: 0 : if (r == -EINVAL)
185 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid calendar spec");
186 [ # # ]: 0 : if (r < 0)
187 : 0 : return r;
188 : :
189 [ # # ]: 0 : if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
190 [ # # ]: 0 : unit_write_settingf(UNIT(t), flags|UNIT_ESCAPE_SPECIFIERS, name,
191 : : "%s=%s", timer_base_to_string(base), str);
192 : :
193 : 0 : TimerValue *v = new(TimerValue, 1);
194 [ # # ]: 0 : if (!v)
195 : 0 : return -ENOMEM;
196 : :
197 : 0 : *v = (TimerValue) {
198 : : .base = base,
199 : 0 : .calendar_spec = TAKE_PTR(c),
200 : : };
201 : :
202 [ # # # # ]: 0 : LIST_PREPEND(value, t->values, v);
203 : : }
204 : :
205 : 0 : return 1;
206 : : };
207 : :
208 : 0 : static int bus_timer_set_transient_property(
209 : : Timer *t,
210 : : const char *name,
211 : : sd_bus_message *message,
212 : : UnitWriteFlags flags,
213 : : sd_bus_error *error) {
214 : :
215 [ # # ]: 0 : Unit *u = UNIT(t);
216 : : int r;
217 : :
218 [ # # ]: 0 : assert(t);
219 [ # # ]: 0 : assert(name);
220 [ # # ]: 0 : assert(message);
221 : :
222 : 0 : flags |= UNIT_PRIVATE;
223 : :
224 [ # # ]: 0 : if (streq(name, "AccuracyUSec"))
225 : 0 : return bus_set_transient_usec(u, name, &t->accuracy_usec, message, flags, error);
226 : :
227 [ # # ]: 0 : if (streq(name, "AccuracySec")) {
228 [ # # ]: 0 : log_notice("Client is using obsolete AccuracySec= transient property, please use AccuracyUSec= instead.");
229 : 0 : return bus_set_transient_usec(u, "AccuracyUSec", &t->accuracy_usec, message, flags, error);
230 : : }
231 : :
232 [ # # ]: 0 : if (streq(name, "RandomizedDelayUSec"))
233 : 0 : return bus_set_transient_usec(u, name, &t->random_usec, message, flags, error);
234 : :
235 [ # # ]: 0 : if (streq(name, "WakeSystem"))
236 : 0 : return bus_set_transient_bool(u, name, &t->wake_system, message, flags, error);
237 : :
238 [ # # ]: 0 : if (streq(name, "Persistent"))
239 : 0 : return bus_set_transient_bool(u, name, &t->persistent, message, flags, error);
240 : :
241 [ # # ]: 0 : if (streq(name, "RemainAfterElapse"))
242 : 0 : return bus_set_transient_bool(u, name, &t->remain_after_elapse, message, flags, error);
243 : :
244 [ # # ]: 0 : if (streq(name, "OnTimezoneChange"))
245 : 0 : return bus_set_transient_bool(u, name, &t->on_timezone_change, message, flags, error);
246 : :
247 [ # # ]: 0 : if (streq(name, "OnClockChange"))
248 : 0 : return bus_set_transient_bool(u, name, &t->on_clock_change, message, flags, error);
249 : :
250 [ # # ]: 0 : if (streq(name, "TimersMonotonic")) {
251 : : const char *base_name;
252 : : usec_t usec;
253 : 0 : bool empty = true;
254 : :
255 : 0 : r = sd_bus_message_enter_container(message, 'a', "(st)");
256 [ # # ]: 0 : if (r < 0)
257 : 0 : return r;
258 : :
259 [ # # ]: 0 : while ((r = sd_bus_message_read(message, "(st)", &base_name, &usec)) > 0) {
260 : : TimerBase b;
261 : :
262 : 0 : b = timer_base_from_string(base_name);
263 [ # # # # ]: 0 : if (b < 0 || b == TIMER_CALENDAR)
264 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
265 : : "Invalid timer base: %s", base_name);
266 : :
267 : 0 : r = timer_add_one_monotonic_spec(t, name, b, flags, usec, error);
268 [ # # ]: 0 : if (r < 0)
269 : 0 : return r;
270 : :
271 : 0 : empty = false;
272 : : }
273 [ # # ]: 0 : if (r < 0)
274 : 0 : return r;
275 : :
276 : 0 : r = sd_bus_message_exit_container(message);
277 [ # # ]: 0 : if (r < 0)
278 : 0 : return r;
279 : :
280 [ # # # # ]: 0 : if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
281 : 0 : timer_free_values(t);
282 : 0 : unit_write_setting(u, flags, name, "OnActiveSec=");
283 : : }
284 : :
285 : 0 : return 1;
286 : :
287 [ # # ]: 0 : } else if (streq(name, "TimersCalendar")) {
288 : : const char *base_name, *str;
289 : 0 : bool empty = true;
290 : :
291 : 0 : r = sd_bus_message_enter_container(message, 'a', "(ss)");
292 [ # # ]: 0 : if (r < 0)
293 : 0 : return r;
294 : :
295 [ # # ]: 0 : while ((r = sd_bus_message_read(message, "(ss)", &base_name, &str)) > 0) {
296 : : TimerBase b;
297 : :
298 : 0 : b = timer_base_from_string(base_name);
299 [ # # ]: 0 : if (b != TIMER_CALENDAR)
300 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
301 : : "Invalid timer base: %s", base_name);
302 : :
303 : 0 : r = timer_add_one_calendar_spec(t, name, b, flags, str, error);
304 [ # # ]: 0 : if (r < 0)
305 : 0 : return r;
306 : :
307 : 0 : empty = false;
308 : : }
309 [ # # ]: 0 : if (r < 0)
310 : 0 : return r;
311 : :
312 : 0 : r = sd_bus_message_exit_container(message);
313 [ # # ]: 0 : if (r < 0)
314 : 0 : return r;
315 : :
316 [ # # # # ]: 0 : if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
317 : 0 : timer_free_values(t);
318 : 0 : unit_write_setting(u, flags, name, "OnCalendar=");
319 : : }
320 : :
321 : 0 : return 1;
322 : :
323 [ # # ]: 0 : } else if (STR_IN_SET(name,
324 : : "OnActiveSec",
325 : : "OnBootSec",
326 : : "OnStartupSec",
327 : : "OnUnitActiveSec",
328 : : "OnUnitInactiveSec")) {
329 : :
330 : : TimerBase b;
331 : : usec_t usec;
332 : :
333 [ # # ]: 0 : log_notice("Client is using obsolete %s= transient property, please use TimersMonotonic= instead.", name);
334 : :
335 : 0 : b = timer_base_from_string(name);
336 [ # # ]: 0 : if (b < 0)
337 : 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown timer base");
338 : :
339 : 0 : r = sd_bus_message_read(message, "t", &usec);
340 [ # # ]: 0 : if (r < 0)
341 : 0 : return r;
342 : :
343 : 0 : return timer_add_one_monotonic_spec(t, name, b, flags, usec, error);
344 : :
345 [ # # ]: 0 : } else if (streq(name, "OnCalendar")) {
346 : :
347 : : const char *str;
348 : :
349 [ # # ]: 0 : log_notice("Client is using obsolete %s= transient property, please use TimersCalendar= instead.", name);
350 : :
351 : 0 : r = sd_bus_message_read(message, "s", &str);
352 [ # # ]: 0 : if (r < 0)
353 : 0 : return r;
354 : :
355 : 0 : return timer_add_one_calendar_spec(t, name, TIMER_CALENDAR, flags, str, error);
356 : : }
357 : :
358 : 0 : return 0;
359 : : }
360 : :
361 : 0 : int bus_timer_set_property(
362 : : Unit *u,
363 : : const char *name,
364 : : sd_bus_message *message,
365 : : UnitWriteFlags mode,
366 : : sd_bus_error *error) {
367 : :
368 : 0 : Timer *t = TIMER(u);
369 : :
370 [ # # ]: 0 : assert(t);
371 [ # # ]: 0 : assert(name);
372 [ # # ]: 0 : assert(message);
373 : :
374 [ # # # # ]: 0 : if (u->transient && u->load_state == UNIT_STUB)
375 : 0 : return bus_timer_set_transient_property(t, name, message, mode, error);
376 : :
377 : 0 : return 0;
378 : : }
|