chiark / gitweb /
util: move close_all_fds() to util.c
[elogind.git] / dbus-job.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23
24 #include "dbus.h"
25 #include "log.h"
26
27 static const char introspection[] =
28         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
29         "<node>"
30         " <interface name=\"org.freedesktop.systemd1.Job\">"
31         "  <method name=\"Cancel\"/>"
32         "  <signal name=\"Changed\"/>"
33         "  <property name=\"Id\" type=\"u\" access=\"read\"/>"
34         "  <property name=\"Unit\" type=\"(so)\" access=\"read\"/>"
35         "  <property name=\"JobType\" type=\"s\" access=\"read\"/>"
36         "  <property name=\"State\" type=\"s\" access=\"read\"/>"
37         " </interface>"
38         BUS_PROPERTIES_INTERFACE
39         BUS_INTROSPECTABLE_INTERFACE
40         "</node>";
41
42 static int bus_job_append_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
43         Job *j = data;
44         const char *state;
45
46         assert(m);
47         assert(i);
48         assert(property);
49         assert(j);
50
51         state = job_state_to_string(j->state);
52
53         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
54                 return -ENOMEM;
55
56         return 0;
57 }
58
59 static int bus_job_append_type(Manager *m, DBusMessageIter *i, const char *property, void *data) {
60         Job *j = data;
61         const char *type;
62
63         assert(m);
64         assert(i);
65         assert(property);
66         assert(j);
67
68         type = job_type_to_string(j->type);
69
70         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &type))
71                 return -ENOMEM;
72
73         return 0;
74 }
75
76 static int bus_job_append_unit(Manager *m, DBusMessageIter *i, const char *property, void *data) {
77         Job *j = data;
78         DBusMessageIter sub;
79         char *p;
80         const char *id;
81
82         assert(m);
83         assert(i);
84         assert(property);
85         assert(j);
86
87         if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
88                 return -ENOMEM;
89
90         if (!(p = unit_dbus_path(j->unit)))
91                 return -ENOMEM;
92
93         id = unit_id(j->unit);
94
95         if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
96             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
97                 free(p);
98                 return -ENOMEM;
99         }
100
101         free(p);
102
103         if (!dbus_message_iter_close_container(i, &sub))
104                 return -ENOMEM;
105
106         return 0;
107 }
108
109 static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusMessage *message) {
110         const BusProperty properties[] = {
111                 { "org.freedesktop.systemd1.Job", "Id",      bus_property_append_uint32, "u",    &j->id },
112                 { "org.freedesktop.systemd1.Job", "State",   bus_job_append_state,       "s",    j      },
113                 { "org.freedesktop.systemd1.Job", "JobType", bus_job_append_type,        "s",    j      },
114                 { "org.freedesktop.systemd1.Job", "Unit",    bus_job_append_unit,        "(so)", j      },
115                 { NULL, NULL, NULL, NULL, NULL }
116         };
117
118         DBusMessage *reply = NULL;
119         Manager *m = j->manager;
120
121         if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Job", "Cancel")) {
122                 if (!(reply = dbus_message_new_method_return(message)))
123                         goto oom;
124
125                 job_free(j);
126
127         } else
128                 return bus_default_message_handler(j->manager, message, introspection, properties);
129
130         if (reply) {
131                 if (!dbus_connection_send(m->api_bus, reply, NULL))
132                         goto oom;
133
134                 dbus_message_unref(reply);
135         }
136
137         return DBUS_HANDLER_RESULT_HANDLED;
138
139 oom:
140         if (reply)
141                 dbus_message_unref(reply);
142
143         return DBUS_HANDLER_RESULT_NEED_MEMORY;
144 }
145
146 static DBusHandlerResult bus_job_message_handler(DBusConnection  *connection, DBusMessage  *message, void *data) {
147         Manager *m = data;
148         Job *j;
149         int r;
150
151         assert(connection);
152         assert(message);
153         assert(m);
154
155         log_debug("Got D-Bus request: %s.%s() on %s",
156                   dbus_message_get_interface(message),
157                   dbus_message_get_member(message),
158                   dbus_message_get_path(message));
159
160         if ((r = manager_get_job_from_dbus_path(m, dbus_message_get_path(message), &j)) < 0) {
161
162                 if (r == -ENOMEM)
163                         return DBUS_HANDLER_RESULT_NEED_MEMORY;
164
165                 if (r == -ENOENT)
166                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
167
168                 return bus_send_error_reply(m, message, NULL, r);
169         }
170
171         return bus_job_message_dispatch(j, message);
172 }
173
174 const DBusObjectPathVTable bus_job_vtable = {
175         .message_function = bus_job_message_handler
176 };
177
178 void bus_job_send_change_signal(Job *j) {
179         char *p = NULL;
180         DBusMessage *m = NULL;
181
182         assert(j);
183         assert(j->in_dbus_queue);
184
185         LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
186         j->in_dbus_queue = false;
187
188         if (set_isempty(j->manager->subscribed))
189                 return;
190
191         if (!(p = job_dbus_path(j)))
192                 goto oom;
193
194         if (j->sent_dbus_new_signal) {
195                 /* Send a change signal */
196
197                 if (!(m = dbus_message_new_signal(p, "org.freedesktop.systemd1.Job", "Changed")))
198                         goto oom;
199         } else {
200                 /* Send a new signal */
201
202                 if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1", "JobNew")))
203                         goto oom;
204
205                 if (!dbus_message_append_args(m,
206                                               DBUS_TYPE_UINT32, &j->id,
207                                               DBUS_TYPE_OBJECT_PATH, &p,
208                                               DBUS_TYPE_INVALID))
209                         goto oom;
210         }
211
212         if (!dbus_connection_send(j->manager->api_bus, m, NULL))
213                 goto oom;
214
215         free(p);
216         dbus_message_unref(m);
217
218         j->sent_dbus_new_signal = true;
219
220         return;
221
222 oom:
223         free(p);
224
225         if (m)
226                 dbus_message_unref(m);
227
228         log_error("Failed to allocate job change signal.");
229 }
230
231 void bus_job_send_removed_signal(Job *j) {
232         char *p = NULL;
233         DBusMessage *m = NULL;
234
235         assert(j);
236
237         if (set_isempty(j->manager->subscribed) || !j->sent_dbus_new_signal)
238                 return;
239
240         if (!(p = job_dbus_path(j)))
241                 goto oom;
242
243         if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1", "JobRemoved")))
244                 goto oom;
245
246         if (!dbus_message_append_args(m,
247                                       DBUS_TYPE_UINT32, &j->id,
248                                       DBUS_TYPE_OBJECT_PATH, &p,
249                                       DBUS_TYPE_INVALID))
250                 goto oom;
251
252         if (!dbus_connection_send(j->manager->api_bus, m, NULL))
253                 goto oom;
254
255         free(p);
256         dbus_message_unref(m);
257
258         return;
259
260 oom:
261         free(p);
262
263         if (m)
264                 dbus_message_unref(m);
265
266         log_error("Failed to allocate job remove signal.");
267 }