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