2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "alloc-util.h"
22 #include "dbus-timer.h"
27 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result
, timer_result
, TimerResult
);
29 static int property_get_monotonic_timers(
32 const char *interface
,
34 sd_bus_message
*reply
,
36 sd_bus_error
*error
) {
46 r
= sd_bus_message_open_container(reply
, 'a', "(stt)");
50 LIST_FOREACH(value
, v
, t
->values
) {
51 _cleanup_free_
char *buf
= NULL
;
55 if (v
->base
== TIMER_CALENDAR
)
58 s
= timer_base_to_string(v
->base
);
59 assert(endswith(s
, "Sec"));
68 memcpy(buf
+l
-3, "USec", 5);
70 r
= sd_bus_message_append(reply
, "(stt)", buf
, v
->value
, v
->next_elapse
);
75 return sd_bus_message_close_container(reply
);
78 static int property_get_calendar_timers(
81 const char *interface
,
83 sd_bus_message
*reply
,
85 sd_bus_error
*error
) {
95 r
= sd_bus_message_open_container(reply
, 'a', "(sst)");
99 LIST_FOREACH(value
, v
, t
->values
) {
100 _cleanup_free_
char *buf
= NULL
;
102 if (v
->base
!= TIMER_CALENDAR
)
105 r
= calendar_spec_to_string(v
->calendar_spec
, &buf
);
109 r
= sd_bus_message_append(reply
, "(sst)", timer_base_to_string(v
->base
), buf
, v
->next_elapse
);
114 return sd_bus_message_close_container(reply
);
117 static int property_get_unit(
120 const char *interface
,
121 const char *property
,
122 sd_bus_message
*reply
,
124 sd_bus_error
*error
) {
126 Unit
*u
= userdata
, *trigger
;
132 trigger
= UNIT_TRIGGER(u
);
134 return sd_bus_message_append(reply
, "s", trigger
? trigger
->id
: "");
137 static int property_get_next_elapse_monotonic(
140 const char *interface
,
141 const char *property
,
142 sd_bus_message
*reply
,
144 sd_bus_error
*error
) {
153 if (t
->next_elapse_monotonic_or_boottime
<= 0)
155 else if (t
->wake_system
) {
158 a
= now(CLOCK_MONOTONIC
);
159 b
= now(clock_boottime_or_monotonic());
161 if (t
->next_elapse_monotonic_or_boottime
+ a
> b
)
162 x
= t
->next_elapse_monotonic_or_boottime
+ a
- b
;
166 x
= t
->next_elapse_monotonic_or_boottime
;
168 return sd_bus_message_append(reply
, "t", x
);
171 const sd_bus_vtable bus_timer_vtable
[] = {
172 SD_BUS_VTABLE_START(0),
173 SD_BUS_PROPERTY("Unit", "s", property_get_unit
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
174 SD_BUS_PROPERTY("TimersMonotonic", "a(stt)", property_get_monotonic_timers
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
175 SD_BUS_PROPERTY("TimersCalendar", "a(sst)", property_get_calendar_timers
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
176 SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec
, offsetof(Timer
, next_elapse_realtime
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
177 SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", property_get_next_elapse_monotonic
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
178 BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer
, last_trigger
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
179 SD_BUS_PROPERTY("Result", "s", property_get_result
, offsetof(Timer
, result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
180 SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec
, offsetof(Timer
, accuracy_usec
), SD_BUS_VTABLE_PROPERTY_CONST
),
181 SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec
, offsetof(Timer
, random_usec
), SD_BUS_VTABLE_PROPERTY_CONST
),
182 SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool
, offsetof(Timer
, persistent
), SD_BUS_VTABLE_PROPERTY_CONST
),
183 SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool
, offsetof(Timer
, wake_system
), SD_BUS_VTABLE_PROPERTY_CONST
),
184 SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool
, offsetof(Timer
, remain_after_elapse
), SD_BUS_VTABLE_PROPERTY_CONST
),
188 static int bus_timer_set_transient_property(
191 sd_bus_message
*message
,
192 UnitSetPropertiesMode mode
,
193 sd_bus_error
*error
) {
206 "OnUnitInactiveSec")) {
209 TimerBase b
= _TIMER_BASE_INVALID
;
212 b
= timer_base_from_string(name
);
216 r
= sd_bus_message_read(message
, "t", &u
);
220 if (mode
!= UNIT_CHECK
) {
221 char time
[FORMAT_TIMESPAN_MAX
];
223 unit_write_drop_in_private_format(UNIT(t
), mode
, name
, "%s=%s", name
, format_timespan(time
, sizeof(time
), u
, USEC_PER_MSEC
));
225 v
= new0(TimerValue
, 1);
232 LIST_PREPEND(value
, t
->values
, v
);
237 } else if (streq(name
, "OnCalendar")) {
240 CalendarSpec
*c
= NULL
;
243 r
= sd_bus_message_read(message
, "s", &str
);
247 if (mode
!= UNIT_CHECK
) {
248 r
= calendar_spec_from_string(str
, &c
);
252 unit_write_drop_in_private_format(UNIT(t
), mode
, name
, "%s=%s", name
, str
);
254 v
= new0(TimerValue
, 1);
256 calendar_spec_free(c
);
260 v
->base
= TIMER_CALENDAR
;
261 v
->calendar_spec
= c
;
263 LIST_PREPEND(value
, t
->values
, v
);
268 } else if (STR_IN_SET(name
, "AccuracyUSec", "AccuracySec")) {
271 if (streq(name
, "AccuracySec"))
272 log_notice("Client is using obsolete AccuracySec= transient property, please use AccuracyUSec= instead.");
274 r
= sd_bus_message_read(message
, "t", &u
);
278 if (mode
!= UNIT_CHECK
) {
279 t
->accuracy_usec
= u
;
280 unit_write_drop_in_private_format(UNIT(t
), mode
, name
, "AccuracySec=" USEC_FMT
"us", u
);
285 } else if (streq(name
, "RandomizedDelayUSec")) {
288 r
= sd_bus_message_read(message
, "t", &u
);
292 if (mode
!= UNIT_CHECK
) {
294 unit_write_drop_in_private_format(UNIT(t
), mode
, name
, "RandomizedDelaySec=" USEC_FMT
"us", u
);
299 } else if (streq(name
, "WakeSystem")) {
302 r
= sd_bus_message_read(message
, "b", &b
);
306 if (mode
!= UNIT_CHECK
) {
308 unit_write_drop_in_private_format(UNIT(t
), mode
, name
, "%s=%s", name
, yes_no(b
));
313 } else if (streq(name
, "RemainAfterElapse")) {
316 r
= sd_bus_message_read(message
, "b", &b
);
320 if (mode
!= UNIT_CHECK
) {
321 t
->remain_after_elapse
= b
;
322 unit_write_drop_in_private_format(UNIT(t
), mode
, name
, "%s=%s", name
, yes_no(b
));
331 int bus_timer_set_property(
334 sd_bus_message
*message
,
335 UnitSetPropertiesMode mode
,
336 sd_bus_error
*error
) {
345 if (u
->transient
&& u
->load_state
== UNIT_STUB
) {
346 r
= bus_timer_set_transient_property(t
, name
, message
, mode
, error
);