chiark / gitweb /
43e785246cd9c053fd50f2cadc7c76273429eb73
[elogind.git] / src / core / dbus-timer.c
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-unit.h"
25 #include "dbus-timer.h"
26 #include "bus-util.h"
27 #include "errno-list.h"
28 #include "strv.h"
29
30 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
31
32 static int property_get_monotonic_timers(
33                 sd_bus *bus,
34                 const char *path,
35                 const char *interface,
36                 const char *property,
37                 sd_bus_message *reply,
38                 void *userdata,
39                 sd_bus_error *error) {
40
41         Timer *t = userdata;
42         TimerValue *v;
43         int r;
44
45         assert(bus);
46         assert(reply);
47         assert(t);
48
49         r = sd_bus_message_open_container(reply, 'a', "(stt)");
50         if (r < 0)
51                 return r;
52
53         LIST_FOREACH(value, v, t->values) {
54                 _cleanup_free_ char *buf = NULL;
55                 const char *s;
56                 size_t l;
57
58                 if (v->base == TIMER_CALENDAR)
59                         continue;
60
61                 s = timer_base_to_string(v->base);
62                 assert(endswith(s, "Sec"));
63
64                 /* s/Sec/USec/ */
65                 l = strlen(s);
66                 buf = new(char, l+2);
67                 if (!buf)
68                         return -ENOMEM;
69
70                 memcpy(buf, s, l-3);
71                 memcpy(buf+l-3, "USec", 5);
72
73                 r = sd_bus_message_append(reply, "(stt)", buf, v->value, v->next_elapse);
74                 if (r < 0)
75                         return r;
76         }
77
78         return sd_bus_message_close_container(reply);
79 }
80
81 static int property_get_calendar_timers(
82                 sd_bus *bus,
83                 const char *path,
84                 const char *interface,
85                 const char *property,
86                 sd_bus_message *reply,
87                 void *userdata,
88                 sd_bus_error *error) {
89
90         Timer *t = userdata;
91         TimerValue *v;
92         int r;
93
94         assert(bus);
95         assert(reply);
96         assert(t);
97
98         r = sd_bus_message_open_container(reply, 'a', "(sst)");
99         if (r < 0)
100                 return r;
101
102         LIST_FOREACH(value, v, t->values) {
103                 _cleanup_free_ char *buf = NULL;
104
105                 if (v->base != TIMER_CALENDAR)
106                         continue;
107
108                 r = calendar_spec_to_string(v->calendar_spec, &buf);
109                 if (r < 0)
110                         return r;
111
112                 r = sd_bus_message_append(reply, "(sst)", timer_base_to_string(v->base), buf, v->next_elapse);
113                 if (r < 0)
114                         return r;
115         }
116
117         return sd_bus_message_close_container(reply);
118 }
119
120 static int property_get_unit(
121                 sd_bus *bus,
122                 const char *path,
123                 const char *interface,
124                 const char *property,
125                 sd_bus_message *reply,
126                 void *userdata,
127                 sd_bus_error *error) {
128
129         Unit *u = userdata, *trigger;
130
131         assert(bus);
132         assert(reply);
133         assert(u);
134
135         trigger = UNIT_TRIGGER(u);
136
137         return sd_bus_message_append(reply, "s", trigger ? trigger->id : "");
138 }
139
140 static int property_get_next_elapse_monotonic(
141                 sd_bus *bus,
142                 const char *path,
143                 const char *interface,
144                 const char *property,
145                 sd_bus_message *reply,
146                 void *userdata,
147                 sd_bus_error *error) {
148
149         Timer *t = userdata;
150         usec_t x;
151
152         assert(bus);
153         assert(reply);
154         assert(t);
155
156         if (t->next_elapse_monotonic_or_boottime <= 0)
157                 x = 0;
158         else if (t->wake_system) {
159                 usec_t a, b;
160
161                 a = now(CLOCK_MONOTONIC);
162                 b = now(CLOCK_BOOTTIME);
163
164                 if (t->next_elapse_monotonic_or_boottime + a > b)
165                         x = t->next_elapse_monotonic_or_boottime + a - b;
166                 else
167                         x = 0;
168         } else
169                 x = t->next_elapse_monotonic_or_boottime;
170
171         return sd_bus_message_append(reply, "t", x);
172 }
173
174 const sd_bus_vtable bus_timer_vtable[] = {
175         SD_BUS_VTABLE_START(0),
176         SD_BUS_PROPERTY("Unit", "s", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
177         SD_BUS_PROPERTY("TimersMonotonic", "a(stt)", property_get_monotonic_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
178         SD_BUS_PROPERTY("TimersCalendar", "a(sst)", property_get_calendar_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
179         SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
180         SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", property_get_next_elapse_monotonic, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
181         BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
182         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
183         SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
184         SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
185         SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
186         SD_BUS_VTABLE_END
187 };
188
189 static int bus_timer_set_transient_property(
190                 Timer *t,
191                 const char *name,
192                 sd_bus_message *message,
193                 UnitSetPropertiesMode mode,
194                 sd_bus_error *error) {
195
196         int r;
197
198         assert(t);
199         assert(name);
200         assert(message);
201
202         if (STR_IN_SET(name,
203                        "OnActiveSec",
204                        "OnBootSec",
205                        "OnStartupSec",
206                        "OnUnitActiveSec",
207                        "OnUnitInactiveSec")) {
208
209                 TimerValue *v;
210                 TimerBase b = _TIMER_BASE_INVALID;
211                 usec_t u = 0;
212
213                 b = timer_base_from_string(name);
214                 if (b < 0)
215                         return -EINVAL;
216
217                 r = sd_bus_message_read(message, "t", &u);
218                 if (r < 0)
219                         return r;
220
221                 if (mode != UNIT_CHECK) {
222                         char time[FORMAT_TIMESPAN_MAX];
223
224                         unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
225
226                         v = new0(TimerValue, 1);
227                         if (!v)
228                                 return -ENOMEM;
229
230                         v->base = b;
231                         v->value = u;
232
233                         LIST_PREPEND(value, t->values, v);
234                 }
235
236                 return 1;
237
238         } else if (streq(name, "OnCalendar")) {
239
240                 TimerValue *v;
241                 CalendarSpec *c = NULL;
242                 const char *str;
243
244                 r = sd_bus_message_read(message, "s", &str);
245                 if (r < 0)
246                         return r;
247
248                 if (mode != UNIT_CHECK) {
249                         r = calendar_spec_from_string(str, &c);
250                         if (r < 0)
251                                 return r;
252
253                         unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, str);
254
255                         v = new0(TimerValue, 1);
256                         if (!v) {
257                                 if (c)
258                                         calendar_spec_free(c);
259                                 return -ENOMEM;
260                         }
261
262                         v->base = TIMER_CALENDAR;
263                         v->calendar_spec = c;
264
265                         LIST_PREPEND(value, t->values, v);
266                 }
267
268                 return 1;
269
270         } else if (streq(name, "AccuracySec")) {
271
272                 usec_t u = 0;
273
274                 r = sd_bus_message_read(message, "t", &u);
275                 if (r < 0)
276                         return r;
277
278                 if (mode != UNIT_CHECK) {
279                         char time[FORMAT_TIMESPAN_MAX];
280
281                         t->accuracy_usec = u;
282                         unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
283                 }
284
285                 return 1;
286
287         } else if (streq(name, "WakeSystem")) {
288
289                 int b;
290
291                 r = sd_bus_message_read(message, "b", &b);
292                 if (r < 0)
293                         return r;
294
295                 if (mode != UNIT_CHECK) {
296                         t->wake_system = b;
297                         unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(t->wake_system));
298                 }
299
300                 return 1;
301
302         }
303
304         return 0;
305 }
306
307 int bus_timer_set_property(
308                 Unit *u,
309                 const char *name,
310                 sd_bus_message *message,
311                 UnitSetPropertiesMode mode,
312                 sd_bus_error *error) {
313
314         Timer *t = TIMER(u);
315         int r;
316
317         assert(t);
318         assert(name);
319         assert(message);
320
321         if (u->transient && u->load_state == UNIT_STUB) {
322                 r = bus_timer_set_transient_property(t, name, message, mode, error);
323                 if (r != 0)
324                         return r;
325         }
326
327         return 0;
328 }