]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-timer.c
Merge pull request #18863 from keszybz/cmdline-escaping
[thirdparty/systemd.git] / src / core / dbus-timer.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
871d7de4 2
b5efdb8a 3#include "alloc-util.h"
40af3d02 4#include "bus-get-properties.h"
b5efdb8a 5#include "dbus-timer.h"
3e3c5a45 6#include "dbus-util.h"
d8a812d1 7#include "strv.h"
b5efdb8a
LP
8#include "timer.h"
9#include "unit.h"
718db961
LP
10
11static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
12
13static 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,
ebcf1f97
LP
19 void *userdata,
20 sd_bus_error *error) {
718db961
LP
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) {
3761902e 35 _cleanup_free_ char *buf = NULL;
718db961 36 const char *s;
03fae018 37 size_t l;
707e5e52 38
718db961 39 if (v->base == TIMER_CALENDAR)
b719810d 40 continue;
03fae018 41
718db961
LP
42 s = timer_base_to_string(v->base);
43 assert(endswith(s, "Sec"));
3761902e 44
b719810d 45 /* s/Sec/USec/ */
718db961 46 l = strlen(s);
b719810d
LP
47 buf = new(char, l+2);
48 if (!buf)
49 return -ENOMEM;
03fae018 50
718db961 51 memcpy(buf, s, l-3);
b719810d 52 memcpy(buf+l-3, "USec", 5);
03fae018 53
718db961
LP
54 r = sd_bus_message_append(reply, "(stt)", buf, v->value, v->next_elapse);
55 if (r < 0)
56 return r;
707e5e52
LP
57 }
58
718db961 59 return sd_bus_message_close_container(reply);
707e5e52
LP
60}
61
718db961
LP
62static 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,
ebcf1f97
LP
68 void *userdata,
69 sd_bus_error *error) {
b719810d 70
718db961
LP
71 Timer *t = userdata;
72 TimerValue *v;
73 int r;
b719810d 74
718db961
LP
75 assert(bus);
76 assert(reply);
77 assert(t);
b719810d 78
718db961
LP
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) {
b719810d 84 _cleanup_free_ char *buf = NULL;
b719810d 85
718db961 86 if (v->base != TIMER_CALENDAR)
b719810d
LP
87 continue;
88
718db961
LP
89 r = calendar_spec_to_string(v->calendar_spec, &buf);
90 if (r < 0)
91 return r;
b719810d 92
718db961
LP
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;
b719810d
LP
96 }
97
718db961 98 return sd_bus_message_close_container(reply);
b719810d
LP
99}
100
dedabea4
LP
101static 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;
dedabea4
LP
111
112 assert(bus);
113 assert(reply);
114 assert(t);
115
79fc8b96
LP
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));
dedabea4
LP
119}
120
718db961
LP
121const sd_bus_vtable bus_timer_vtable[] = {
122 SD_BUS_VTABLE_START(0),
54138a8d 123 SD_BUS_PROPERTY("Unit", "s", bus_property_get_triggered_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
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),
efebb613
LP
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),
454f7158 128 SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
dedabea4
LP
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),
718db961 131 SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc 132 SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
6f5d7998 133 SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
acf24a1a 134 SD_BUS_PROPERTY("FixedRandomDelay", "b", bus_property_get_bool, offsetof(Timer, fixed_random_delay), SD_BUS_VTABLE_PROPERTY_CONST),
06642d17 135 SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
dedabea4 136 SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
3e0c30ac 137 SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST),
718db961 138 SD_BUS_VTABLE_END
d200735e 139};
d8a812d1 140
cd87f634
ZJS
141static 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 char ts[FORMAT_TIMESPAN_MAX];
151 TimerValue *v;
152
153 unit_write_settingf(UNIT(t), flags|UNIT_ESCAPE_SPECIFIERS, name,
154 "%s=%s",
155 timer_base_to_string(base),
156 format_timespan(ts, sizeof ts, usec, USEC_PER_MSEC));
157
158 v = new(TimerValue, 1);
159 if (!v)
160 return -ENOMEM;
161
162 *v = (TimerValue) {
163 .base = base,
164 .value = usec,
165 };
166
167 LIST_PREPEND(value, t->values, v);
168 }
169
170 return 1;
171}
172
d00a52c7
ZJS
173static int timer_add_one_calendar_spec(
174 Timer *t,
175 const char *name,
176 TimerBase base,
177 UnitWriteFlags flags,
178 const char *str,
179 sd_bus_error *error) {
180
181 _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
182 int r;
183
184 r = calendar_spec_from_string(str, &c);
185 if (r == -EINVAL)
1b09b81c 186 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid calendar spec");
d00a52c7
ZJS
187 if (r < 0)
188 return r;
189
190 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
191 unit_write_settingf(UNIT(t), flags|UNIT_ESCAPE_SPECIFIERS, name,
192 "%s=%s", timer_base_to_string(base), str);
193
194 TimerValue *v = new(TimerValue, 1);
195 if (!v)
196 return -ENOMEM;
197
198 *v = (TimerValue) {
199 .base = base,
23f8fbb3 200 .calendar_spec = TAKE_PTR(c),
d00a52c7
ZJS
201 };
202
203 LIST_PREPEND(value, t->values, v);
204 }
205
206 return 1;
207};
208
d8a812d1
WC
209static int bus_timer_set_transient_property(
210 Timer *t,
211 const char *name,
212 sd_bus_message *message,
2e59b241 213 UnitWriteFlags flags,
d8a812d1
WC
214 sd_bus_error *error) {
215
3e3c5a45 216 Unit *u = UNIT(t);
d8a812d1
WC
217 int r;
218
219 assert(t);
220 assert(name);
221 assert(message);
222
2e59b241
LP
223 flags |= UNIT_PRIVATE;
224
3e3c5a45
YW
225 if (streq(name, "AccuracyUSec"))
226 return bus_set_transient_usec(u, name, &t->accuracy_usec, message, flags, error);
227
228 if (streq(name, "AccuracySec")) {
229 log_notice("Client is using obsolete AccuracySec= transient property, please use AccuracyUSec= instead.");
230 return bus_set_transient_usec(u, "AccuracyUSec", &t->accuracy_usec, message, flags, error);
231 }
232
233 if (streq(name, "RandomizedDelayUSec"))
234 return bus_set_transient_usec(u, name, &t->random_usec, message, flags, error);
235
acf24a1a
KG
236 if (streq(name, "FixedRandomDelay"))
237 return bus_set_transient_bool(u, name, &t->fixed_random_delay, message, flags, error);
238
3e3c5a45
YW
239 if (streq(name, "WakeSystem"))
240 return bus_set_transient_bool(u, name, &t->wake_system, message, flags, error);
241
242 if (streq(name, "Persistent"))
243 return bus_set_transient_bool(u, name, &t->persistent, message, flags, error);
244
245 if (streq(name, "RemainAfterElapse"))
246 return bus_set_transient_bool(u, name, &t->remain_after_elapse, message, flags, error);
247
efebb613
LP
248 if (streq(name, "OnTimezoneChange"))
249 return bus_set_transient_bool(u, name, &t->on_timezone_change, message, flags, error);
250
251 if (streq(name, "OnClockChange"))
252 return bus_set_transient_bool(u, name, &t->on_clock_change, message, flags, error);
253
3e3c5a45
YW
254 if (streq(name, "TimersMonotonic")) {
255 const char *base_name;
cd87f634 256 usec_t usec;
3e3c5a45
YW
257 bool empty = true;
258
259 r = sd_bus_message_enter_container(message, 'a', "(st)");
260 if (r < 0)
261 return r;
262
263 while ((r = sd_bus_message_read(message, "(st)", &base_name, &usec)) > 0) {
264 TimerBase b;
265
266 b = timer_base_from_string(base_name);
267 if (b < 0 || b == TIMER_CALENDAR)
cd87f634
ZJS
268 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
269 "Invalid timer base: %s", base_name);
3e3c5a45 270
cd87f634
ZJS
271 r = timer_add_one_monotonic_spec(t, name, b, flags, usec, error);
272 if (r < 0)
273 return r;
3e3c5a45
YW
274
275 empty = false;
276 }
277 if (r < 0)
278 return r;
279
280 r = sd_bus_message_exit_container(message);
281 if (r < 0)
282 return r;
283
284 if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
285 timer_free_values(t);
286 unit_write_setting(u, flags, name, "OnActiveSec=");
287 }
288
289 return 1;
290
291 } else if (streq(name, "TimersCalendar")) {
292 const char *base_name, *str;
293 bool empty = true;
294
295 r = sd_bus_message_enter_container(message, 'a', "(ss)");
296 if (r < 0)
297 return r;
298
299 while ((r = sd_bus_message_read(message, "(ss)", &base_name, &str)) > 0) {
3e3c5a45
YW
300 TimerBase b;
301
302 b = timer_base_from_string(base_name);
303 if (b != TIMER_CALENDAR)
d00a52c7
ZJS
304 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
305 "Invalid timer base: %s", base_name);
3e3c5a45 306
d00a52c7 307 r = timer_add_one_calendar_spec(t, name, b, flags, str, error);
3e3c5a45
YW
308 if (r < 0)
309 return r;
310
3e3c5a45
YW
311 empty = false;
312 }
313 if (r < 0)
314 return r;
315
316 r = sd_bus_message_exit_container(message);
317 if (r < 0)
318 return r;
319
320 if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
321 timer_free_values(t);
322 unit_write_setting(u, flags, name, "OnCalendar=");
323 }
324
325 return 1;
326
327 } else if (STR_IN_SET(name,
d8a812d1
WC
328 "OnActiveSec",
329 "OnBootSec",
330 "OnStartupSec",
331 "OnUnitActiveSec",
332 "OnUnitInactiveSec")) {
333
cd87f634
ZJS
334 TimerBase b;
335 usec_t usec;
3e3c5a45
YW
336
337 log_notice("Client is using obsolete %s= transient property, please use TimersMonotonic= instead.", name);
d8a812d1
WC
338
339 b = timer_base_from_string(name);
340 if (b < 0)
170d4026 341 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown timer base %s", name);
d8a812d1 342
3e3c5a45 343 r = sd_bus_message_read(message, "t", &usec);
d8a812d1
WC
344 if (r < 0)
345 return r;
346
cd87f634 347 return timer_add_one_monotonic_spec(t, name, b, flags, usec, error);
d8a812d1
WC
348
349 } else if (streq(name, "OnCalendar")) {
350
d8a812d1
WC
351 const char *str;
352
3e3c5a45
YW
353 log_notice("Client is using obsolete %s= transient property, please use TimersCalendar= instead.", name);
354
d8a812d1
WC
355 r = sd_bus_message_read(message, "s", &str);
356 if (r < 0)
357 return r;
358
d00a52c7 359 return timer_add_one_calendar_spec(t, name, TIMER_CALENDAR, flags, str, error);
d8a812d1
WC
360 }
361
362 return 0;
363}
364
365int bus_timer_set_property(
366 Unit *u,
367 const char *name,
368 sd_bus_message *message,
2e59b241 369 UnitWriteFlags mode,
d8a812d1
WC
370 sd_bus_error *error) {
371
372 Timer *t = TIMER(u);
d8a812d1
WC
373
374 assert(t);
375 assert(name);
376 assert(message);
377
2e59b241
LP
378 if (u->transient && u->load_state == UNIT_STUB)
379 return bus_timer_set_transient_property(t, name, message, mode, error);
d8a812d1
WC
380
381 return 0;
382}