chiark / gitweb /
unit: use weaker dependencies between mount and device units in --user mode
[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-timer.h"
25 #include "bus-util.h"
26 #include "strv.h"
27
28 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
29
30 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         Timer *t = userdata;
40         TimerValue *v;
41         int r;
42
43         assert(bus);
44         assert(reply);
45         assert(t);
46
47         r = sd_bus_message_open_container(reply, 'a', "(stt)");
48         if (r < 0)
49                 return r;
50
51         LIST_FOREACH(value, v, t->values) {
52                 _cleanup_free_ char *buf = NULL;
53                 const char *s;
54                 size_t l;
55
56                 if (v->base == TIMER_CALENDAR)
57                         continue;
58
59                 s = timer_base_to_string(v->base);
60                 assert(endswith(s, "Sec"));
61
62                 /* s/Sec/USec/ */
63                 l = strlen(s);
64                 buf = new(char, l+2);
65                 if (!buf)
66                         return -ENOMEM;
67
68                 memcpy(buf, s, l-3);
69                 memcpy(buf+l-3, "USec", 5);
70
71                 r = sd_bus_message_append(reply, "(stt)", buf, v->value, v->next_elapse);
72                 if (r < 0)
73                         return r;
74         }
75
76         return sd_bus_message_close_container(reply);
77 }
78
79 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         Timer *t = userdata;
89         TimerValue *v;
90         int r;
91
92         assert(bus);
93         assert(reply);
94         assert(t);
95
96         r = sd_bus_message_open_container(reply, 'a', "(sst)");
97         if (r < 0)
98                 return r;
99
100         LIST_FOREACH(value, v, t->values) {
101                 _cleanup_free_ char *buf = NULL;
102
103                 if (v->base != TIMER_CALENDAR)
104                         continue;
105
106                 r = calendar_spec_to_string(v->calendar_spec, &buf);
107                 if (r < 0)
108                         return r;
109
110                 r = sd_bus_message_append(reply, "(sst)", timer_base_to_string(v->base), buf, v->next_elapse);
111                 if (r < 0)
112                         return r;
113         }
114
115         return sd_bus_message_close_container(reply);
116 }
117
118 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         Unit *u = userdata, *trigger;
128
129         assert(bus);
130         assert(reply);
131         assert(u);
132
133         trigger = UNIT_TRIGGER(u);
134
135         return sd_bus_message_append(reply, "s", trigger ? trigger->id : "");
136 }
137
138 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         Timer *t = userdata;
148         usec_t x;
149
150         assert(bus);
151         assert(reply);
152         assert(t);
153
154         if (t->next_elapse_monotonic_or_boottime <= 0)
155                 x = 0;
156         else if (t->wake_system) {
157                 usec_t a, b;
158
159                 a = now(CLOCK_MONOTONIC);
160                 b = now(CLOCK_BOOTTIME);
161
162                 if (t->next_elapse_monotonic_or_boottime + a > b)
163                         x = t->next_elapse_monotonic_or_boottime + a - b;
164                 else
165                         x = 0;
166         } else
167                 x = t->next_elapse_monotonic_or_boottime;
168
169         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 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         assert(t);
197         assert(name);
198         assert(message);
199
200         if (STR_IN_SET(name,
201                        "OnActiveSec",
202                        "OnBootSec",
203                        "OnStartupSec",
204                        "OnUnitActiveSec",
205                        "OnUnitInactiveSec")) {
206
207                 TimerValue *v;
208                 TimerBase b = _TIMER_BASE_INVALID;
209                 usec_t u = 0;
210
211                 b = timer_base_from_string(name);
212                 if (b < 0)
213                         return -EINVAL;
214
215                 r = sd_bus_message_read(message, "t", &u);
216                 if (r < 0)
217                         return r;
218
219                 if (mode != UNIT_CHECK) {
220                         char time[FORMAT_TIMESPAN_MAX];
221
222                         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                         v = new0(TimerValue, 1);
225                         if (!v)
226                                 return -ENOMEM;
227
228                         v->base = b;
229                         v->value = u;
230
231                         LIST_PREPEND(value, t->values, v);
232                 }
233
234                 return 1;
235
236         } else if (streq(name, "OnCalendar")) {
237
238                 TimerValue *v;
239                 CalendarSpec *c = NULL;
240                 const char *str;
241
242                 r = sd_bus_message_read(message, "s", &str);
243                 if (r < 0)
244                         return r;
245
246                 if (mode != UNIT_CHECK) {
247                         r = calendar_spec_from_string(str, &c);
248                         if (r < 0)
249                                 return r;
250
251                         unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, str);
252
253                         v = new0(TimerValue, 1);
254                         if (!v) {
255                                 if (c)
256                                         calendar_spec_free(c);
257                                 return -ENOMEM;
258                         }
259
260                         v->base = TIMER_CALENDAR;
261                         v->calendar_spec = c;
262
263                         LIST_PREPEND(value, t->values, v);
264                 }
265
266                 return 1;
267
268         } else if (streq(name, "AccuracySec")) {
269
270                 usec_t u = 0;
271
272                 r = sd_bus_message_read(message, "t", &u);
273                 if (r < 0)
274                         return r;
275
276                 if (mode != UNIT_CHECK) {
277                         char time[FORMAT_TIMESPAN_MAX];
278
279                         t->accuracy_usec = u;
280                         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                 return 1;
284
285         } else if (streq(name, "WakeSystem")) {
286
287                 int b;
288
289                 r = sd_bus_message_read(message, "b", &b);
290                 if (r < 0)
291                         return r;
292
293                 if (mode != UNIT_CHECK) {
294                         t->wake_system = b;
295                         unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(t->wake_system));
296                 }
297
298                 return 1;
299
300         }
301
302         return 0;
303 }
304
305 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         Timer *t = TIMER(u);
313         int r;
314
315         assert(t);
316         assert(name);
317         assert(message);
318
319         if (u->transient && u->load_state == UNIT_STUB) {
320                 r = bus_timer_set_transient_property(t, name, message, mode, error);
321                 if (r != 0)
322                         return r;
323         }
324
325         return 0;
326 }