1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "bus-get-properties.h"
5 #include "dbus-timer.h"
11 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result
, timer_result
, TimerResult
);
13 static int property_get_monotonic_timers(
16 const char *interface
,
18 sd_bus_message
*reply
,
20 sd_bus_error
*error
) {
30 r
= sd_bus_message_open_container(reply
, 'a', "(stt)");
34 LIST_FOREACH(value
, v
, t
->values
) {
35 _cleanup_free_
char *buf
= NULL
;
39 if (v
->base
== TIMER_CALENDAR
)
42 s
= timer_base_to_string(v
->base
);
43 assert(endswith(s
, "Sec"));
52 memcpy(buf
+l
-3, "USec", 5);
54 r
= sd_bus_message_append(reply
, "(stt)", buf
, v
->value
, v
->next_elapse
);
59 return sd_bus_message_close_container(reply
);
62 static int property_get_calendar_timers(
65 const char *interface
,
67 sd_bus_message
*reply
,
69 sd_bus_error
*error
) {
79 r
= sd_bus_message_open_container(reply
, 'a', "(sst)");
83 LIST_FOREACH(value
, v
, t
->values
) {
84 _cleanup_free_
char *buf
= NULL
;
86 if (v
->base
!= TIMER_CALENDAR
)
89 r
= calendar_spec_to_string(v
->calendar_spec
, &buf
);
93 r
= sd_bus_message_append(reply
, "(sst)", timer_base_to_string(v
->base
), buf
, v
->next_elapse
);
98 return sd_bus_message_close_container(reply
);
101 static int property_get_next_elapse_monotonic(
104 const char *interface
,
105 const char *property
,
106 sd_bus_message
*reply
,
108 sd_bus_error
*error
) {
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
));
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
),
141 static int timer_add_one_monotonic_spec(
145 UnitWriteFlags flags
,
147 sd_bus_error
*error
) {
149 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
150 char ts
[FORMAT_TIMESPAN_MAX
];
153 unit_write_settingf(UNIT(t
), flags
|UNIT_ESCAPE_SPECIFIERS
, name
,
155 timer_base_to_string(base
),
156 format_timespan(ts
, sizeof ts
, usec
, USEC_PER_MSEC
));
158 v
= new(TimerValue
, 1);
167 LIST_PREPEND(value
, t
->values
, v
);
173 static int timer_add_one_calendar_spec(
177 UnitWriteFlags flags
,
179 sd_bus_error
*error
) {
181 _cleanup_(calendar_spec_freep
) CalendarSpec
*c
= NULL
;
184 r
= calendar_spec_from_string(str
, &c
);
186 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid calendar spec");
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
);
194 TimerValue
*v
= new(TimerValue
, 1);
200 .calendar_spec
= TAKE_PTR(c
),
203 LIST_PREPEND(value
, t
->values
, v
);
209 static int bus_timer_set_transient_property(
212 sd_bus_message
*message
,
213 UnitWriteFlags flags
,
214 sd_bus_error
*error
) {
223 flags
|= UNIT_PRIVATE
;
225 if (streq(name
, "AccuracyUSec"))
226 return bus_set_transient_usec(u
, name
, &t
->accuracy_usec
, message
, flags
, error
);
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
);
233 if (streq(name
, "RandomizedDelayUSec"))
234 return bus_set_transient_usec(u
, name
, &t
->random_usec
, message
, flags
, error
);
236 if (streq(name
, "FixedRandomDelay"))
237 return bus_set_transient_bool(u
, name
, &t
->fixed_random_delay
, message
, flags
, error
);
239 if (streq(name
, "WakeSystem"))
240 return bus_set_transient_bool(u
, name
, &t
->wake_system
, message
, flags
, error
);
242 if (streq(name
, "Persistent"))
243 return bus_set_transient_bool(u
, name
, &t
->persistent
, message
, flags
, error
);
245 if (streq(name
, "RemainAfterElapse"))
246 return bus_set_transient_bool(u
, name
, &t
->remain_after_elapse
, message
, flags
, error
);
248 if (streq(name
, "OnTimezoneChange"))
249 return bus_set_transient_bool(u
, name
, &t
->on_timezone_change
, message
, flags
, error
);
251 if (streq(name
, "OnClockChange"))
252 return bus_set_transient_bool(u
, name
, &t
->on_clock_change
, message
, flags
, error
);
254 if (streq(name
, "TimersMonotonic")) {
255 const char *base_name
;
259 r
= sd_bus_message_enter_container(message
, 'a', "(st)");
263 while ((r
= sd_bus_message_read(message
, "(st)", &base_name
, &usec
)) > 0) {
266 b
= timer_base_from_string(base_name
);
267 if (b
< 0 || b
== TIMER_CALENDAR
)
268 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
,
269 "Invalid timer base: %s", base_name
);
271 r
= timer_add_one_monotonic_spec(t
, name
, b
, flags
, usec
, error
);
280 r
= sd_bus_message_exit_container(message
);
284 if (!UNIT_WRITE_FLAGS_NOOP(flags
) && empty
) {
285 timer_free_values(t
);
286 unit_write_setting(u
, flags
, name
, "OnActiveSec=");
291 } else if (streq(name
, "TimersCalendar")) {
292 const char *base_name
, *str
;
295 r
= sd_bus_message_enter_container(message
, 'a', "(ss)");
299 while ((r
= sd_bus_message_read(message
, "(ss)", &base_name
, &str
)) > 0) {
302 b
= timer_base_from_string(base_name
);
303 if (b
!= TIMER_CALENDAR
)
304 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
,
305 "Invalid timer base: %s", base_name
);
307 r
= timer_add_one_calendar_spec(t
, name
, b
, flags
, str
, error
);
316 r
= sd_bus_message_exit_container(message
);
320 if (!UNIT_WRITE_FLAGS_NOOP(flags
) && empty
) {
321 timer_free_values(t
);
322 unit_write_setting(u
, flags
, name
, "OnCalendar=");
327 } else if (STR_IN_SET(name
,
332 "OnUnitInactiveSec")) {
337 log_notice("Client is using obsolete %s= transient property, please use TimersMonotonic= instead.", name
);
339 b
= timer_base_from_string(name
);
341 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown timer base %s", name
);
343 r
= sd_bus_message_read(message
, "t", &usec
);
347 return timer_add_one_monotonic_spec(t
, name
, b
, flags
, usec
, error
);
349 } else if (streq(name
, "OnCalendar")) {
353 log_notice("Client is using obsolete %s= transient property, please use TimersCalendar= instead.", name
);
355 r
= sd_bus_message_read(message
, "s", &str
);
359 return timer_add_one_calendar_spec(t
, name
, TIMER_CALENDAR
, flags
, str
, error
);
365 int bus_timer_set_property(
368 sd_bus_message
*message
,
370 sd_bus_error
*error
) {
378 if (u
->transient
&& u
->load_state
== UNIT_STUB
)
379 return bus_timer_set_transient_property(t
, name
, message
, mode
, error
);