chiark / gitweb /
client: add a very basic Vala command line tool
[elogind.git] / dbus-unit.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 #include <errno.h>
4
5 #include "dbus.h"
6 #include "log.h"
7
8 static const char introspection[] =
9         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
10         "<node>"
11         " <!-- you suck -->"
12         " <interface name=\"org.freedesktop.systemd1.Unit\">"
13         "  <property name=\"Id\" type=\"s\" access=\"read\"/>"
14         "  <property name=\"Description\" type=\"s\" access=\"read\"/>"
15         "  <property name=\"LoadState\" type=\"s\" access=\"read\"/>"
16         "  <property name=\"ActiveState\" type=\"s\" access=\"read\"/>"
17         "  <property name=\"LoadPath\" type=\"s\" access=\"read\"/>"
18         "  <property name=\"ActiveEnterTimestamp\" type=\"t\" access=\"read\"/>"
19         "  <property name=\"ActiveExitTimestamp\" type=\"t\" access=\"read\"/>"
20         "  <property name=\"CanReload\" type=\"b\" access=\"read\"/>"
21         "  <property name=\"CanStart\" type=\"b\" access=\"read\"/>"
22         "  <property name=\"Job\" type=\"(uo)\" access=\"read\"/>"
23         " </interface>"
24         BUS_PROPERTIES_INTERFACE
25         BUS_INTROSPECTABLE_INTERFACE
26         "</node>";
27
28 static int bus_unit_append_id(Manager *m, DBusMessageIter *i, const char *property, void *data) {
29         Unit *u = data;
30         const char *id;
31
32         assert(m);
33         assert(i);
34         assert(property);
35         assert(u);
36
37         id = unit_id(u);
38
39         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
40                 return -ENOMEM;
41
42         return 0;
43 }
44
45 static int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data) {
46         Unit *u = data;
47         const char *d;
48
49         assert(m);
50         assert(i);
51         assert(property);
52         assert(u);
53
54         d = unit_description(u);
55
56         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
57                 return -ENOMEM;
58
59         return 0;
60 }
61
62 static int bus_unit_append_load_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
63         Unit *u = data;
64         const char *state;
65
66         assert(m);
67         assert(i);
68         assert(property);
69         assert(u);
70
71         state = unit_load_state_to_string(u->meta.load_state);
72
73         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
74                 return -ENOMEM;
75
76         return 0;
77 }
78
79 static int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
80         Unit *u = data;
81         const char *state;
82
83         assert(m);
84         assert(i);
85         assert(property);
86         assert(u);
87
88         state = unit_active_state_to_string(unit_active_state(u));
89
90         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
91                 return -ENOMEM;
92
93         return 0;
94 }
95
96 static int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data) {
97         Unit *u = data;
98         dbus_bool_t b;
99
100         assert(m);
101         assert(i);
102         assert(property);
103         assert(u);
104
105         b = unit_can_reload(u);
106
107         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
108                 return -ENOMEM;
109
110         return 0;
111 }
112
113 static int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data) {
114         Unit *u = data;
115         dbus_bool_t b;
116
117         assert(m);
118         assert(i);
119         assert(property);
120         assert(u);
121
122         b = unit_can_start(u);
123
124         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
125                 return -ENOMEM;
126
127         return 0;
128 }
129
130 static int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data) {
131         Unit *u = data;
132         DBusMessageIter sub;
133         char *p;
134
135         assert(m);
136         assert(i);
137         assert(property);
138         assert(u);
139
140         if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
141                 return -ENOMEM;
142
143         if (u->meta.job) {
144
145                 if (!(p = job_dbus_path(u->meta.job)))
146                         return -ENOMEM;
147
148                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->meta.job->id) ||
149                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
150                         free(p);
151                         return -ENOMEM;
152                 }
153         } else {
154                 uint32_t id = 0;
155
156                 /* No job, so let's fill in some placeholder
157                  * data. Since we need to fill in a valid path we
158                  * simple point to ourselves. */
159
160                 if (!(p = unit_dbus_path(u)))
161                         return -ENOMEM;
162
163                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) ||
164                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
165                         free(p);
166                         return -ENOMEM;
167                 }
168         }
169
170         free(p);
171
172         if (!dbus_message_iter_close_container(i, &sub))
173                 return -ENOMEM;
174
175         return 0;
176 }
177
178 static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusMessage *message) {
179
180         const BusProperty properties[] = {
181                 { "org.freedesktop.systemd1.Unit", "Id",                   bus_unit_append_id,           "s",    u                               },
182                 { "org.freedesktop.systemd1.Unit", "Description",          bus_unit_append_description,  "s",    u                               },
183                 { "org.freedesktop.systemd1.Unit", "LoadState",            bus_unit_append_load_state,   "s",    u                               },
184                 { "org.freedesktop.systemd1.Unit", "ActiveState",          bus_unit_append_active_state, "s",    u                               },
185                 { "org.freedesktop.systemd1.Unit", "LoadPath",             bus_property_append_string,   "s",    u->meta.load_path               },
186                 { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestamp", bus_property_append_uint64,   "t",    &u->meta.active_enter_timestamp },
187                 { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp",  bus_property_append_uint64,   "t",    &u->meta.active_exit_timestamp  },
188                 { "org.freedesktop.systemd1.Unit", "CanReload",            bus_unit_append_can_reload,   "b",    u                               },
189                 { "org.freedesktop.systemd1.Unit", "CanStart",             bus_unit_append_can_start,    "b",    u                               },
190                 { "org.freedesktop.systemd1.Unit", "Job",                  bus_unit_append_job,          "(uo)", u                               },
191                 { NULL, NULL, NULL, NULL, NULL }
192         };
193
194         return bus_default_message_handler(u->meta.manager, message, introspection, properties);
195 }
196
197 static DBusHandlerResult bus_unit_message_handler(DBusConnection  *connection, DBusMessage  *message, void *data) {
198         Manager *m = data;
199         Unit *u;
200         int r;
201
202         assert(connection);
203         assert(message);
204         assert(m);
205
206         log_debug("Got D-Bus request: %s.%s() on %s",
207                   dbus_message_get_interface(message),
208                   dbus_message_get_member(message),
209                   dbus_message_get_path(message));
210
211         if ((r = manager_get_unit_from_dbus_path(m, dbus_message_get_path(message), &u)) < 0) {
212
213                 if (r == -ENOMEM)
214                         return DBUS_HANDLER_RESULT_NEED_MEMORY;
215
216                 if (r == -ENOENT)
217                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
218
219                 return bus_send_error_reply(m, message, NULL, r);
220         }
221
222         return bus_unit_message_dispatch(u, message);
223 }
224
225 const DBusObjectPathVTable bus_unit_vtable = {
226         .message_function = bus_unit_message_handler
227 };