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 : }
|