tizen 2.3 release
[framework/system/deviced.git] / src / shared / dbus.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <stdint.h>
24 #include <errno.h>
25
26 #include "common.h"
27 #include "log.h"
28 #include "dbus.h"
29
30 /* -1 is a default timeout value, it's converted to 25*1000 internally. */
31 #define DBUS_REPLY_TIMEOUT      (-1)
32
33 struct pending_call_data {
34         dbus_pending_cb func;
35         void *data;
36 };
37
38 int append_variant(DBusMessageIter *iter, const char *sig, char *param[])
39 {
40         char *ch;
41         int i;
42         int int_type;
43         dbus_bool_t bool_type;
44         uint64_t int64_type;
45         DBusMessageIter arr;
46         struct dbus_byte *byte;
47
48         if (!sig || !param)
49                 return 0;
50
51         for (ch = (char*)sig, i = 0; *ch != '\0'; ++i, ++ch) {
52                 switch (*ch) {
53                 case 'b':
54                         bool_type = (atoi(param[i])) ? TRUE:FALSE;
55                         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &bool_type);
56                         break;
57                 case 'i':
58                         int_type = atoi(param[i]);
59                         dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &int_type);
60                         break;
61                 case 'u':
62                         int_type = strtoul(param[i], NULL, 10);
63                         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &int_type);
64                         break;
65                 case 't':
66                         int64_type = atoll(param[i]);
67                         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &int64_type);
68                         break;
69                 case 's':
70                         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &param[i]);
71                         break;
72                 case 'a':
73                         ++i, ++ch;
74                         switch (*ch) {
75                         case 'y':
76                                 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &arr);
77                                 byte = (struct dbus_byte*)param[i];
78                                 dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &(byte->data), byte->size);
79                                 dbus_message_iter_close_container(iter, &arr);
80                                 break;
81                         default:
82                                 break;
83                         }
84                         break;
85                 default:
86                         return -EINVAL;
87                 }
88         }
89
90         return 0;
91 }
92
93 DBusMessage *dbus_method_sync_with_reply(const char *dest, const char *path,
94                 const char *interface, const char *method,
95                 const char *sig, char *param[])
96 {
97         DBusConnection *conn;
98         DBusMessage *msg;
99         DBusMessageIter iter;
100         DBusMessage *reply;
101         DBusError err;
102         int r;
103
104         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
105         if (!conn) {
106                 _E("dbus_bus_get error");
107                 return NULL;
108         }
109
110         msg = dbus_message_new_method_call(dest, path, interface, method);
111         if (!msg) {
112                 _E("dbus_message_new_method_call(%s:%s-%s)",
113                         path, interface, method);
114                 return NULL;
115         }
116
117         dbus_message_iter_init_append(msg, &iter);
118         r = append_variant(&iter, sig, param);
119         if (r < 0) {
120                 _E("append_variant error(%d) %s %s:%s-%s",
121                         r, dest, path, interface, method);
122                 dbus_message_unref(msg);
123                 return NULL;
124         }
125
126         dbus_error_init(&err);
127
128         reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
129         if (!reply) {
130                 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
131                         dest, path, interface, method);
132         }
133
134         if (dbus_error_is_set(&err)) {
135                 _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
136                         err.name, err.message, dest, path, interface, method);
137                 dbus_error_free(&err);
138                 reply = NULL;
139         }
140
141         dbus_message_unref(msg);
142         return reply;
143 }
144
145 int dbus_method_sync(const char *dest, const char *path,
146                 const char *interface, const char *method,
147                 const char *sig, char *param[])
148 {
149         DBusConnection *conn;
150         DBusMessage *msg;
151         DBusMessageIter iter;
152         DBusMessage *reply;
153         DBusError err;
154         int ret, result;
155
156         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
157         if (!conn) {
158                 _E("dbus_bus_get error");
159                 return -EPERM;
160         }
161
162         msg = dbus_message_new_method_call(dest, path, interface, method);
163         if (!msg) {
164                 _E("dbus_message_new_method_call(%s:%s-%s)",
165                         path, interface, method);
166                 return -EBADMSG;
167         }
168
169         dbus_message_iter_init_append(msg, &iter);
170         ret = append_variant(&iter, sig, param);
171         if (ret < 0) {
172                 _E("append_variant error(%d) %s %s:%s-%s",
173                         ret, dest, path, interface, method);
174                 dbus_message_unref(msg);
175                 return ret;
176         }
177
178         dbus_error_init(&err);
179
180         reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
181         dbus_message_unref(msg);
182         if (!reply) {
183                 _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
184                         err.name, err.message, dest, path, interface, method);
185                 dbus_error_free(&err);
186                 return -ECOMM;
187         }
188
189         ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
190         dbus_message_unref(reply);
191         if (!ret) {
192                 _E("no message : [%s:%s] %s %s:%s-%s",
193                         err.name, err.message, dest, path, interface, method);
194                 dbus_error_free(&err);
195                 return -ENOMSG;
196         }
197
198         return result;
199 }
200
201 int dbus_method_sync_timeout(const char *dest, const char *path,
202                 const char *interface, const char *method,
203                 const char *sig, char *param[], int timeout)
204 {
205         DBusConnection *conn;
206         DBusMessage *msg;
207         DBusMessageIter iter;
208         DBusMessage *reply;
209         DBusError err;
210         int ret, result;
211
212         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
213         if (!conn) {
214                 _E("dbus_bus_get error");
215                 return -EPERM;
216         }
217
218         msg = dbus_message_new_method_call(dest, path, interface, method);
219         if (!msg) {
220                 _E("dbus_message_new_method_call(%s:%s-%s)",
221                         path, interface, method);
222                 return -EBADMSG;
223         }
224
225         dbus_message_iter_init_append(msg, &iter);
226         ret = append_variant(&iter, sig, param);
227         if (ret < 0) {
228                 _E("append_variant error(%d) %s %s:%s-%s",
229                         ret, dest, path, interface, method);
230                 dbus_message_unref(msg);
231                 return ret;
232         }
233
234         dbus_error_init(&err);
235
236         reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
237         dbus_message_unref(msg);
238         if (!reply) {
239                 _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
240                         err.name, err.message, dest, path, interface, method);
241                 dbus_error_free(&err);
242                 return -ECOMM;
243         }
244
245         ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
246         dbus_message_unref(reply);
247         if (!ret) {
248                 _E("no message : [%s:%s] %s %s:%s-%s",
249                         err.name, err.message, dest, path, interface, method);
250                 dbus_error_free(&err);
251                 return -ENOMSG;
252         }
253
254         return result;
255 }
256
257 int dbus_method_async(const char *dest, const char *path,
258                 const char *interface, const char *method,
259                 const char *sig, char *param[])
260 {
261         DBusConnection *conn;
262         DBusMessage *msg;
263         DBusMessageIter iter;
264         int ret;
265
266         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
267         if (!conn) {
268                 _E("dbus_bus_get error");
269                 return -EPERM;
270         }
271
272         msg = dbus_message_new_method_call(dest, path, interface, method);
273         if (!msg) {
274                 _E("dbus_message_new_method_call(%s:%s-%s)",
275                         path, interface, method);
276                 return -EBADMSG;
277         }
278
279         dbus_message_iter_init_append(msg, &iter);
280         ret = append_variant(&iter, sig, param);
281         if (ret < 0) {
282                 _E("append_variant error(%d) %s %s:%s-%s",
283                         ret, dest, path, interface, method);
284                 dbus_message_unref(msg);
285                 return ret;
286         }
287
288         ret = dbus_connection_send(conn, msg, NULL);
289         dbus_message_unref(msg);
290         if (ret != TRUE) {
291                 _E("dbus_connection_send error(%s %s:%s-%s)",
292                         dest, path, interface, method);
293                 return -ECOMM;
294         }
295
296         return 0;
297 }
298
299 static void cb_pending(DBusPendingCall *pending, void *user_data)
300 {
301         DBusMessage *msg;
302         DBusError err;
303         struct pending_call_data *data = user_data;
304         int ret;
305
306         ret = dbus_pending_call_get_completed(pending);
307         if (!ret) {
308                 _I("dbus_pending_call_get_completed() fail");
309                 dbus_pending_call_unref(pending);
310                 return;
311         }
312
313         dbus_error_init(&err);
314         msg = dbus_pending_call_steal_reply(pending);
315         if (!msg) {
316                 _E("no message : [%s:%s]", err.name, err.message);
317
318                 if (data->func) {
319                         dbus_set_error(&err, "org.tizen.system.deviced.NoReply",
320                                         "There was no reply to this method call");
321                         data->func(data->data, NULL, &err);
322                         dbus_error_free(&err);
323                 }
324                 return;
325         }
326
327         ret = dbus_set_error_from_message(&err, msg);
328         if (ret) {
329                 _E("error msg : [%s:%s]", err.name, err.message);
330
331                 if (data->func)
332                         data->func(data->data, NULL, &err);
333                 dbus_error_free(&err);
334         } else {
335                 if (data->func)
336                         data->func(data->data, msg, &err);
337         }
338
339         dbus_message_unref(msg);
340         dbus_pending_call_unref(pending);
341 }
342
343 int dbus_method_async_with_reply(const char *dest, const char *path,
344                 const char *interface, const char *method,
345                 const char *sig, char *param[], dbus_pending_cb cb, int timeout, void *data)
346 {
347         DBusConnection *conn;
348         DBusMessage *msg;
349         DBusMessageIter iter;
350         DBusPendingCall *pending = NULL;
351         struct pending_call_data *pdata;
352         int ret;
353
354         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
355         if (!conn) {
356                 _E("dbus_bus_get error");
357                 return -EPERM;
358         }
359
360         msg = dbus_message_new_method_call(dest, path, interface, method);
361         if (!msg) {
362                 _E("dbus_message_new_method_call(%s:%s-%s)",
363                         path, interface, method);
364                 return -EBADMSG;
365         }
366
367         dbus_message_iter_init_append(msg, &iter);
368         ret = append_variant(&iter, sig, param);
369         if (ret < 0) {
370                 _E("append_variant error(%d)%s %s:%s-%s",
371                         ret, dest, path, interface, method);
372                 dbus_message_unref(msg);
373                 return ret;
374         }
375
376         ret = dbus_connection_send_with_reply(conn, msg, &pending, timeout);
377         if (!ret) {
378                 dbus_message_unref(msg);
379                 _E("dbus_connection_send error(%s %s:%s-%s)",
380                         dest, path, interface, method);
381                 return -ECOMM;
382         }
383
384         dbus_message_unref(msg);
385
386         if (cb && pending) {
387                 pdata = malloc(sizeof(struct pending_call_data));
388                 if (!pdata)
389                         return -ENOMEM;
390
391                 pdata->func = cb;
392                 pdata->data = data;
393
394                 ret = dbus_pending_call_set_notify(pending, cb_pending, pdata, free);
395                 if (!ret) {
396                         free(pdata);
397                         dbus_pending_call_cancel(pending);
398                         return -ECOMM;
399                 }
400         }
401
402         return 0;
403 }
404
405 int check_systemd_active(void)
406 {
407         int ret = FALSE;
408         DBusError err;
409         DBusMessage *msg;
410         DBusMessageIter iter, sub;
411         const char *state;
412         char *pa[2];
413
414         pa[0] = "org.freedesktop.systemd1.Unit";
415         pa[1] = "ActiveState";
416
417         _I("%s %s", pa[0], pa[1]);
418
419         msg = dbus_method_sync_with_reply("org.freedesktop.systemd1",
420                         "/org/freedesktop/systemd1/unit/default_2etarget",
421                         "org.freedesktop.DBus.Properties",
422                         "Get", "ss", pa);
423         if (!msg)
424                 return -EBADMSG;
425
426         dbus_error_init(&err);
427
428         if (!dbus_message_iter_init(msg, &iter) ||
429             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
430                 goto out;
431
432         dbus_message_iter_recurse(&iter, &sub);
433
434         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
435                 ret = -EBADMSG;
436                 goto out;
437         }
438
439         dbus_message_iter_get_basic(&sub, &state);
440
441         if (strncmp(state, "active", 6) == 0)
442                 ret = TRUE;
443 out:
444         dbus_message_unref(msg);
445         dbus_error_free(&err);
446         return ret;
447 }
448
449 static void __CONSTRUCTOR__ dbus_init(void)
450 {
451         dbus_threads_init_default();
452 }