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