Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2010 Lennart Poettering
7 :
8 : systemd is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as published by
10 : the Free Software Foundation; either version 2.1 of the License, or
11 : (at your option) any later version.
12 :
13 : systemd is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public License
19 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 : ***/
21 :
22 : #include "unit.h"
23 : #include "timer.h"
24 : #include "dbus-timer.h"
25 : #include "bus-util.h"
26 : #include "strv.h"
27 :
28 0 : static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
29 :
30 0 : static int property_get_monotonic_timers(
31 : sd_bus *bus,
32 : const char *path,
33 : const char *interface,
34 : const char *property,
35 : sd_bus_message *reply,
36 : void *userdata,
37 : sd_bus_error *error) {
38 :
39 0 : Timer *t = userdata;
40 : TimerValue *v;
41 : int r;
42 :
43 0 : assert(bus);
44 0 : assert(reply);
45 0 : assert(t);
46 :
47 0 : r = sd_bus_message_open_container(reply, 'a', "(stt)");
48 0 : if (r < 0)
49 0 : return r;
50 :
51 0 : LIST_FOREACH(value, v, t->values) {
52 0 : _cleanup_free_ char *buf = NULL;
53 : const char *s;
54 : size_t l;
55 :
56 0 : if (v->base == TIMER_CALENDAR)
57 0 : continue;
58 :
59 0 : s = timer_base_to_string(v->base);
60 0 : assert(endswith(s, "Sec"));
61 :
62 : /* s/Sec/USec/ */
63 0 : l = strlen(s);
64 0 : buf = new(char, l+2);
65 0 : if (!buf)
66 0 : return -ENOMEM;
67 :
68 0 : memcpy(buf, s, l-3);
69 0 : memcpy(buf+l-3, "USec", 5);
70 :
71 0 : r = sd_bus_message_append(reply, "(stt)", buf, v->value, v->next_elapse);
72 0 : if (r < 0)
73 0 : return r;
74 : }
75 :
76 0 : return sd_bus_message_close_container(reply);
77 : }
78 :
79 0 : static int property_get_calendar_timers(
80 : sd_bus *bus,
81 : const char *path,
82 : const char *interface,
83 : const char *property,
84 : sd_bus_message *reply,
85 : void *userdata,
86 : sd_bus_error *error) {
87 :
88 0 : Timer *t = userdata;
89 : TimerValue *v;
90 : int r;
91 :
92 0 : assert(bus);
93 0 : assert(reply);
94 0 : assert(t);
95 :
96 0 : r = sd_bus_message_open_container(reply, 'a', "(sst)");
97 0 : if (r < 0)
98 0 : return r;
99 :
100 0 : LIST_FOREACH(value, v, t->values) {
101 0 : _cleanup_free_ char *buf = NULL;
102 :
103 0 : if (v->base != TIMER_CALENDAR)
104 0 : continue;
105 :
106 0 : r = calendar_spec_to_string(v->calendar_spec, &buf);
107 0 : if (r < 0)
108 0 : return r;
109 :
110 0 : r = sd_bus_message_append(reply, "(sst)", timer_base_to_string(v->base), buf, v->next_elapse);
111 0 : if (r < 0)
112 0 : return r;
113 : }
114 :
115 0 : return sd_bus_message_close_container(reply);
116 : }
117 :
118 0 : static int property_get_unit(
119 : sd_bus *bus,
120 : const char *path,
121 : const char *interface,
122 : const char *property,
123 : sd_bus_message *reply,
124 : void *userdata,
125 : sd_bus_error *error) {
126 :
127 0 : Unit *u = userdata, *trigger;
128 :
129 0 : assert(bus);
130 0 : assert(reply);
131 0 : assert(u);
132 :
133 0 : trigger = UNIT_TRIGGER(u);
134 :
135 0 : return sd_bus_message_append(reply, "s", trigger ? trigger->id : "");
136 : }
137 :
138 0 : static int property_get_next_elapse_monotonic(
139 : sd_bus *bus,
140 : const char *path,
141 : const char *interface,
142 : const char *property,
143 : sd_bus_message *reply,
144 : void *userdata,
145 : sd_bus_error *error) {
146 :
147 0 : Timer *t = userdata;
148 : usec_t x;
149 :
150 0 : assert(bus);
151 0 : assert(reply);
152 0 : assert(t);
153 :
154 0 : if (t->next_elapse_monotonic_or_boottime <= 0)
155 0 : x = 0;
156 0 : else if (t->wake_system) {
157 : usec_t a, b;
158 :
159 0 : a = now(CLOCK_MONOTONIC);
160 0 : b = now(CLOCK_BOOTTIME);
161 :
162 0 : if (t->next_elapse_monotonic_or_boottime + a > b)
163 0 : x = t->next_elapse_monotonic_or_boottime + a - b;
164 : else
165 0 : x = 0;
166 : } else
167 0 : x = t->next_elapse_monotonic_or_boottime;
168 :
169 0 : return sd_bus_message_append(reply, "t", x);
170 : }
171 :
172 : const sd_bus_vtable bus_timer_vtable[] = {
173 : SD_BUS_VTABLE_START(0),
174 : SD_BUS_PROPERTY("Unit", "s", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
175 : SD_BUS_PROPERTY("TimersMonotonic", "a(stt)", property_get_monotonic_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
176 : SD_BUS_PROPERTY("TimersCalendar", "a(sst)", property_get_calendar_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
177 : SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
178 : SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", property_get_next_elapse_monotonic, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
179 : BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
180 : SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
181 : SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_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_VTABLE_END
185 : };
186 :
187 0 : static int bus_timer_set_transient_property(
188 : Timer *t,
189 : const char *name,
190 : sd_bus_message *message,
191 : UnitSetPropertiesMode mode,
192 : sd_bus_error *error) {
193 :
194 : int r;
195 :
196 0 : assert(t);
197 0 : assert(name);
198 0 : assert(message);
199 :
200 0 : if (STR_IN_SET(name,
201 : "OnActiveSec",
202 : "OnBootSec",
203 : "OnStartupSec",
204 : "OnUnitActiveSec",
205 : "OnUnitInactiveSec")) {
206 :
207 : TimerValue *v;
208 0 : TimerBase b = _TIMER_BASE_INVALID;
209 0 : usec_t u = 0;
210 :
211 0 : b = timer_base_from_string(name);
212 0 : if (b < 0)
213 0 : return -EINVAL;
214 :
215 0 : r = sd_bus_message_read(message, "t", &u);
216 0 : if (r < 0)
217 0 : return r;
218 :
219 0 : if (mode != UNIT_CHECK) {
220 : char time[FORMAT_TIMESPAN_MAX];
221 :
222 0 : unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
223 :
224 0 : v = new0(TimerValue, 1);
225 0 : if (!v)
226 0 : return -ENOMEM;
227 :
228 0 : v->base = b;
229 0 : v->value = u;
230 :
231 0 : LIST_PREPEND(value, t->values, v);
232 : }
233 :
234 0 : return 1;
235 :
236 0 : } else if (streq(name, "OnCalendar")) {
237 :
238 : TimerValue *v;
239 0 : CalendarSpec *c = NULL;
240 : const char *str;
241 :
242 0 : r = sd_bus_message_read(message, "s", &str);
243 0 : if (r < 0)
244 0 : return r;
245 :
246 0 : if (mode != UNIT_CHECK) {
247 0 : r = calendar_spec_from_string(str, &c);
248 0 : if (r < 0)
249 0 : return r;
250 :
251 0 : unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, str);
252 :
253 0 : v = new0(TimerValue, 1);
254 0 : if (!v) {
255 0 : if (c)
256 0 : calendar_spec_free(c);
257 0 : return -ENOMEM;
258 : }
259 :
260 0 : v->base = TIMER_CALENDAR;
261 0 : v->calendar_spec = c;
262 :
263 0 : LIST_PREPEND(value, t->values, v);
264 : }
265 :
266 0 : return 1;
267 :
268 0 : } else if (streq(name, "AccuracySec")) {
269 :
270 0 : usec_t u = 0;
271 :
272 0 : r = sd_bus_message_read(message, "t", &u);
273 0 : if (r < 0)
274 0 : return r;
275 :
276 0 : if (mode != UNIT_CHECK) {
277 : char time[FORMAT_TIMESPAN_MAX];
278 :
279 0 : t->accuracy_usec = u;
280 0 : unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
281 : }
282 :
283 0 : return 1;
284 :
285 0 : } else if (streq(name, "WakeSystem")) {
286 :
287 : int b;
288 :
289 0 : r = sd_bus_message_read(message, "b", &b);
290 0 : if (r < 0)
291 0 : return r;
292 :
293 0 : if (mode != UNIT_CHECK) {
294 0 : t->wake_system = b;
295 0 : unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(t->wake_system));
296 : }
297 :
298 0 : return 1;
299 :
300 : }
301 :
302 0 : return 0;
303 : }
304 :
305 0 : int bus_timer_set_property(
306 : Unit *u,
307 : const char *name,
308 : sd_bus_message *message,
309 : UnitSetPropertiesMode mode,
310 : sd_bus_error *error) {
311 :
312 0 : Timer *t = TIMER(u);
313 : int r;
314 :
315 0 : assert(t);
316 0 : assert(name);
317 0 : assert(message);
318 :
319 0 : if (u->transient && u->load_state == UNIT_STUB) {
320 0 : r = bus_timer_set_transient_property(t, name, message, mode, error);
321 0 : if (r != 0)
322 0 : return r;
323 : }
324 :
325 0 : return 0;
326 : }
|