usb_moded 0.86.0+mer58
usb_moded-dbus.c
Go to the documentation of this file.
1
34
36#include "usb_moded-dbus.h"
37
38#include "usb_moded.h"
40#include "usb_moded-control.h"
41#include "usb_moded-log.h"
42#include "usb_moded-modes.h"
43#include "usb_moded-network.h"
44
45#include <sys/stat.h>
46
47#include "../dbus-gmain/dbus-gmain.h"
48
49#ifdef SAILFISH_ACCESS_CONTROL
50# include <sailfishaccesscontrol.h>
51#endif
52
53/* ========================================================================= *
54 * Constants
55 * ========================================================================= */
56
57#define INIT_DONE_OBJECT "/com/nokia/startup/signal"
58#define INIT_DONE_INTERFACE "com.nokia.startup.signal"
59#define INIT_DONE_SIGNAL "init_done"
60#define INIT_DONE_MATCH "type='signal',interface='"INIT_DONE_INTERFACE"',member='"INIT_DONE_SIGNAL"'"
61
62# define PID_UNKNOWN ((pid_t)-1)
63
64/* ========================================================================= *
65 * Types
66 * ========================================================================= */
67
69
75typedef struct {
77 int type;
78
80 const char *member;
81
84
86 const char *args;
88
91#define ADD_METHOD(NAME, FUNC, ARGS) {\
92 .type = DBUS_MESSAGE_TYPE_METHOD_CALL,\
93 .member = NAME,\
94 .handler = FUNC,\
95 .args = ARGS,\
96}
97
100#define ADD_SIGNAL(NAME, ARGS) {\
101 .type = DBUS_MESSAGE_TYPE_SIGNAL,\
102 .member = NAME,\
103 .handler = 0,\
104 .args = ARGS,\
105}
106
109#define ADD_SENTINEL {\
110 .type = DBUS_MESSAGE_TYPE_INVALID,\
111 .member = 0,\
112 .handler = 0,\
113 .args = 0,\
114}
115
118typedef struct
119{
121 const char *interface;
122
126
129typedef struct
130{
132 const char *object;
133
137
144 DBusMessage *msg;
145
147 int type;
148
150 const char *sender;
151
153 const char *object;
154
156 const char *interface;
157
159 const char *member;
160
163
166
169
171 DBusMessage *rsp;
172};
173
174/* ========================================================================= *
175 * Prototypes
176 * ========================================================================= */
177
178/* ------------------------------------------------------------------------- *
179 * MEMBER_INFO
180 * ------------------------------------------------------------------------- */
181
182static void member_info_introspect(const member_info_t *self, FILE *file);
183
184/* ------------------------------------------------------------------------- *
185 * INTERFACE_INFO
186 * ------------------------------------------------------------------------- */
187
188static const member_info_t *interface_info_get_member(const interface_info_t *self, const char *member);
189static void interface_info_introspect(const interface_info_t *self, FILE *file);
190
191/* ------------------------------------------------------------------------- *
192 * OBJECT_INFO
193 * ------------------------------------------------------------------------- */
194
195static const interface_info_t *object_info_get_interface (const object_info_t *self, const char *interface);
196static void object_info_introspect (const object_info_t *self, FILE *file, const char *interface);
197static char *object_info_get_introspect_xml(const object_info_t *self, const char *interface);
198
199/* ------------------------------------------------------------------------- *
200 * INTROSPECTABLE
201 * ------------------------------------------------------------------------- */
202
203static void introspectable_introspect_cb(umdbus_context_t *context);
204
205/* ------------------------------------------------------------------------- *
206 * USB_MODED
207 * ------------------------------------------------------------------------- */
208
209static void usb_moded_state_request_cb (umdbus_context_t *context);
210static void usb_moded_target_state_get_cb (umdbus_context_t *context);
211static void usb_moded_target_config_get_cb (umdbus_context_t *context);
212static void usb_moded_state_set_cb (umdbus_context_t *context);
213static void usb_moded_config_set_cb (umdbus_context_t *context);
214static void usb_moded_config_get_cb (umdbus_context_t *context);
215static void usb_moded_mode_list_cb (umdbus_context_t *context);
216static void usb_moded_available_modes_get_cb (umdbus_context_t *context);
217static void usb_moded_available_modes_for_user_cb(umdbus_context_t *context);
218static void usb_moded_mode_hide_cb (umdbus_context_t *context);
219static void usb_moded_mode_unhide_cb (umdbus_context_t *context);
220static void usb_moded_hidden_get_cb (umdbus_context_t *context);
221static void usb_moded_whitelisted_modes_get_cb (umdbus_context_t *context);
222static void usb_moded_whitelisted_modes_set_cb (umdbus_context_t *context);
223static void usb_moded_user_config_clear_cb (umdbus_context_t *context);
224static void usb_moded_whitelisted_set_cb (umdbus_context_t *context);
225static void usb_moded_network_set_cb (umdbus_context_t *context);
226static void usb_moded_network_get_cb (umdbus_context_t *context);
227static void usb_moded_rescue_off_cb (umdbus_context_t *context);
228
229/* ------------------------------------------------------------------------- *
230 * UMDBUS
231 * ------------------------------------------------------------------------- */
232
233static const object_info_t *umdbus_get_object_info (const char *object);
235void umdbus_dump_busconfig_xml (void);
236void umdbus_send_config_signal (const char *section, const char *key, const char *value);
237static DBusHandlerResult umdbus_msg_handler (DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data);
238DBusConnection *umdbus_get_connection (void);
239gboolean umdbus_init_connection (void);
240gboolean umdbus_init_service (void);
241static void umdbus_cleanup_service (void);
242void umdbus_cleanup (void);
243static DBusMessage *umdbus_new_signal (const char *signal_name);
244static int umdbus_send_signal_ex (const char *signal_name, const char *content);
245static void umdbus_send_legacy_signal (const char *state_ind);
246void umdbus_send_current_state_signal (const char *state_ind);
247static bool umdbus_append_basic_entry (DBusMessageIter *iter, const char *key, int type, const void *val);
248static bool umdbus_append_int32_entry (DBusMessageIter *iter, const char *key, int val);
249static bool umdbus_append_string_entry (DBusMessageIter *iter, const char *key, const char *val);
250static bool umdbus_append_mode_details (DBusMessage *msg, const char *mode_name);
251static void umdbus_send_mode_details_signal (const char *mode_name);
252void umdbus_send_target_state_signal (const char *state_ind);
253void umdbus_send_event_signal (const char *state_ind);
254int umdbus_send_error_signal (const char *error);
255int umdbus_send_supported_modes_signal (const char *supported_modes);
256int umdbus_send_available_modes_signal (const char *available_modes);
257int umdbus_send_hidden_modes_signal (const char *hidden_modes);
258int umdbus_send_whitelisted_modes_signal(const char *whitelist);
259static void umdbus_get_name_owner_cb (DBusPendingCall *pc, void *aptr);
260gboolean umdbus_get_name_owner_async (const char *name, usb_moded_get_name_owner_fn cb, DBusPendingCall **ppc);
261static uid_t umdbus_get_sender_uid (const char *name);
262const char *umdbus_arg_type_repr (int type);
263const char *umdbus_arg_type_signature (int type);
264const char *umdbus_msg_type_repr (int type);
265bool umdbus_parser_init (DBusMessageIter *iter, DBusMessage *msg);
266int umdbus_parser_at_type (DBusMessageIter *iter);
267bool umdbus_parser_at_end (DBusMessageIter *iter);
268bool umdbus_parser_require_type (DBusMessageIter *iter, int type, bool strict);
269bool umdbus_parser_get_bool (DBusMessageIter *iter, bool *pval);
270bool umdbus_parser_get_int (DBusMessageIter *iter, int *pval);
271bool umdbus_parser_get_string (DBusMessageIter *iter, const char **pval);
272bool umdbus_parser_get_object (DBusMessageIter *iter, const char **pval);
273bool umdbus_parser_get_variant (DBusMessageIter *iter, DBusMessageIter *val);
274bool umdbus_parser_get_array (DBusMessageIter *iter, DBusMessageIter *val);
275bool umdbus_parser_get_struct (DBusMessageIter *iter, DBusMessageIter *val);
276bool umdbus_parser_get_entry (DBusMessageIter *iter, DBusMessageIter *val);
277bool umdbus_append_init (DBusMessageIter *iter, DBusMessage *msg);
278bool umdbus_open_container (DBusMessageIter *iter, DBusMessageIter *sub, int type, const char *sign);
279bool umdbus_close_container (DBusMessageIter *iter, DBusMessageIter *sub, bool success);
280bool umdbus_append_basic_value (DBusMessageIter *iter, int type, const DBusBasicValue *val);
281bool umdbus_append_basic_variant (DBusMessageIter *iter, int type, const DBusBasicValue *val);
282bool umdbus_append_bool (DBusMessageIter *iter, bool val);
283bool umdbus_append_int (DBusMessageIter *iter, int val);
284bool umdbus_append_string (DBusMessageIter *iter, const char *val);
285bool umdbus_append_bool_variant (DBusMessageIter *iter, bool val);
286bool umdbus_append_int_variant (DBusMessageIter *iter, int val);
287bool umdbus_append_string_variant (DBusMessageIter *iter, const char *val);
288bool umdbus_append_args_va (DBusMessageIter *iter, int type, va_list va);
289bool umdbus_append_args (DBusMessageIter *iter, int arg_type, ...);
290DBusMessage *umdbus_blocking_call (DBusConnection *con, const char *dst, const char *obj, const char *iface, const char *meth, DBusError *err, int arg_type, ...);
291bool umdbus_parse_reply (DBusMessage *rsp, int arg_type, ...);
292
293/* ========================================================================= *
294 * Data
295 * ========================================================================= */
296
297static DBusConnection *umdbus_connection = NULL;
298static gboolean umdbus_service_name_acquired = FALSE;
299
300/* ========================================================================= *
301 * MEMBER_INFO
302 * ========================================================================= */
303
304static void
305member_info_introspect(const member_info_t *self, FILE *file)
306{
307 LOG_REGISTER_CONTEXT;
308
309 switch( self->type ) {
310 case DBUS_MESSAGE_TYPE_METHOD_CALL:
311 /* All method call handlers are Introspectable */
312 if( self->args )
313 fprintf(file, " <method name=\"%s\">\n%s </method>\n", self->member, self->args);
314 else
315 fprintf(file, " <method name=\"%s\"/>\n", self->member);
316 break;
317 case DBUS_MESSAGE_TYPE_SIGNAL:
318 /* Only dummy signal handlers are Introspectable */
319 if( self->handler )
320 break;
321 if( self->args )
322 fprintf(file, " <signal name=\"%s\">\n%s </signal>\n", self->member, self->args);
323 else
324 fprintf(file, " <signal name=\"%s\"/>\n", self->member);
325 break;
326 default:
327 break;
328 }
329}
330
331/* ========================================================================= *
332 * INTERFACE_INFO
333 * ========================================================================= */
334
335static const member_info_t *
336interface_info_get_member(const interface_info_t *self, const char *member)
337{
338 LOG_REGISTER_CONTEXT;
339
340 const member_info_t *mem = 0;
341
342 if( !self || !member )
343 goto EXIT;
344
345 for( size_t i = 0; self->members[i].member; ++i ) {
346 if( strcmp(self->members[i].member, member) )
347 continue;
348 mem = &self->members[i];
349 break;
350 }
351EXIT:
352 return mem;
353}
354
355static void
356interface_info_introspect(const interface_info_t *self, FILE *file)
357{
358 LOG_REGISTER_CONTEXT;
359
360 fprintf(file, " <interface name=\"%s\">\n", self->interface);
361 for( size_t i = 0; self->members[i].member; ++i )
362 member_info_introspect(&self->members[i], file);
363 fprintf(file, " </interface>\n");
364}
365
366/* ========================================================================= *
367 * OBJECT_INFO
368 * ========================================================================= */
369
370static const interface_info_t *
371object_info_get_interface(const object_info_t *self, const char *interface)
372{
373 LOG_REGISTER_CONTEXT;
374
375 const interface_info_t *ifc = 0;
376
377 if( !self || !interface )
378 goto EXIT;
379
380 for( size_t i = 0; self->interfaces[i]; ++i ) {
381 if( strcmp(self->interfaces[i]->interface, interface) )
382 continue;
383 ifc = self->interfaces[i];
384 break;
385 }
386EXIT:
387 return ifc;
388}
389
390static void
391object_info_introspect(const object_info_t *self, FILE *file, const char *interface)
392{
393 LOG_REGISTER_CONTEXT;
394
395 if( !self || !file )
396 goto EXIT;
397
398 static const char dtd[] =
399 "<!DOCTYPE node PUBLIC\n"
400 " \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
401 " \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
402
403 fprintf(file, "%s\n", dtd);
404
405 fprintf(file, "<node name=\"%s\">\n", self->object);
406 for( size_t i = 0; self->interfaces[i]; ++i ) {
407 /* Optionally skip all but requested interface */
408 if( interface && strcmp(self->interfaces[i]->interface, interface) )
409 continue;
410 interface_info_introspect(self->interfaces[i], file);
411 }
412
413 /* ASSUMED: self is in an statically allocated array where potential
414 * child nodes are located after it.
415 */
416 const char *parent = self->object;
417 if( !strcmp(parent, "/") )
418 parent = "";
419 size_t n = strlen(parent);
420 for( const object_info_t *obj = self + 1; obj->object; ++obj ) {
421 const char *child = obj->object;
422 if( strncmp(parent, child, n) )
423 continue;
424 if( child[n] != '/' )
425 continue;
426 child += n + 1;
427 if( strchr(child, '/' ) )
428 continue;
429 fprintf(file, " <node name=\"%s\"/>\n", child);
430 }
431
432 fprintf(file, "</node>\n");
433EXIT:
434 return;
435}
436
437static char *
438object_info_get_introspect_xml(const object_info_t *self, const char *interface)
439{
440 LOG_REGISTER_CONTEXT;
441
442 char *text = 0;
443
444 if( self ) {
445 size_t size = 0;
446 FILE *file = open_memstream(&text, &size);
447 object_info_introspect(self, file, interface);
448 fclose(file);
449 }
450
451 return text;
452}
453
454/* ========================================================================= *
455 * INTROSPECTABLE -- org.freedesktop.DBus.Introspectable
456 * ========================================================================= */
457
458static void
459introspectable_introspect_cb(umdbus_context_t *context)
460{
461 LOG_REGISTER_CONTEXT;
462
463 char *text = object_info_get_introspect_xml(context->object_info, 0);
464 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
465 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);
466 free(text);
467}
468
469static const member_info_t introspectable_members[] =
470{
471 ADD_METHOD("Introspect",
472 introspectable_introspect_cb,
473 " <arg name=\"xml\" type=\"s\" direction=\"out\"/>\n"),
475};
476
477static const interface_info_t introspectable_interface = {
478 .interface = "org.freedesktop.DBus.Introspectable",
479 .members = introspectable_members
480};
481
482/* ========================================================================= *
483 * PEER -- org.freedesktop.DBus.Peer
484 * ========================================================================= */
485
486static const member_info_t peer_members[] =
487{
488 /* Note: Introspect glue only - libdbus handles these internally */
489 ADD_METHOD("Ping",
490 0,
491 0),
492 ADD_METHOD("GetMachineId",
493 0,
494 " <arg direction=\"out\" name=\"machine_uuid\" type=\"s\"/>\n"),
496};
497
498static const interface_info_t peer_interface = {
499 .interface = "org.freedesktop.DBus.Peer",
500 .members = peer_members
501};
502
503/* ========================================================================= *
504 * USB_MODED -- com.meego.usb_moded
505 * ========================================================================= */
506
507/* ------------------------------------------------------------------------- *
508 * mode transition
509 * ------------------------------------------------------------------------- */
510
513static void
514usb_moded_state_request_cb(umdbus_context_t *context)
515{
516 LOG_REGISTER_CONTEXT;
517
518 const char *mode = control_get_external_mode();
519 /* To the outside we want to keep CHARGING and CHARGING_FALLBACK the same */
520 if( !strcmp(MODE_CHARGING_FALLBACK, mode) )
521 mode = MODE_CHARGING;
522 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
523 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &mode, DBUS_TYPE_INVALID);
524}
525
528static void
529usb_moded_target_state_get_cb(umdbus_context_t *context)
530{
531 LOG_REGISTER_CONTEXT;
532
533 const char *mode = control_get_target_mode();
534 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
535 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &mode, DBUS_TYPE_INVALID);
536}
537
540static void
541usb_moded_target_config_get_cb(umdbus_context_t *context)
542{
543 LOG_REGISTER_CONTEXT;
544
545 const char *mode = control_get_target_mode();
546 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
547 umdbus_append_mode_details(context->rsp, mode);
548}
549
554static void
555usb_moded_state_set_cb(umdbus_context_t *context)
556{
557 LOG_REGISTER_CONTEXT;
558
559 const char *mode = control_get_external_mode();
560 char *use = 0;
561 DBusError err = DBUS_ERROR_INIT;
562 uid_t uid = umdbus_get_sender_uid(context->sender);
563
564 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID) ) {
565 log_err("parse error: %s: %s", err.name, err.message);
566 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
567 }
568 else if( !usbmoded_is_mode_permitted(use, uid) ) {
569 /* Insufficient permissions */
570 log_warning("Mode '%s' is not allowed for uid %d", use, uid);
571 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_ACCESS_DENIED, context->member);
572 }
573 else if( control_get_cable_state() != CABLE_STATE_PC_CONNECTED ) {
574 /* Mode change makes no sence unless we have a PC connection */
575 log_warning("Mode '%s' requested while not connected to pc", use);
576 }
577 else if( common_valid_mode(use) ) {
578 /* Mode does not exist */
579 log_warning("Unknown mode '%s' requested", use);
580 }
581 else if( !g_strcmp0(mode, MODE_BUSY) ) {
582 /* In middle of a pending mode switch */
583 log_warning("Mode '%s' requested while busy", use);
584 }
585 else if( !control_select_mode(use) ) {
586 /* Requested mode could not be activated */
587 log_warning("Mode '%s' was rejected", use);
588 }
589 else {
590 /* Mode switch initiated (or requested mode already active) */
591 log_debug("Mode '%s' requested", use);
592
593 /* Acknowledge that the mode request was accepted */
594 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
595 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID);
596 }
597
598 /* Default to returning a generic error context->rsp */
599 if( !context->rsp )
600 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_FAILED, context->member);
601
602 dbus_error_free(&err);
603}
604
605/* ------------------------------------------------------------------------- *
606 * default mode
607 * ------------------------------------------------------------------------- */
608
611static void
612usb_moded_config_set_cb(umdbus_context_t *context)
613{
614 LOG_REGISTER_CONTEXT;
615
616 char *config = 0;
617 DBusError err = DBUS_ERROR_INIT;
618 uid_t uid = umdbus_get_sender_uid(context->sender);
619
620 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID) ) {
621 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
622 }
623 else {
624 /* error checking is done when setting configuration */
625 int ret = config_set_mode_setting(config, uid);
626 if( SET_CONFIG_OK(ret) ) {
627 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
628 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
629 }
630 else {
631 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, config);
632 }
633 }
634 dbus_error_free(&err);
635}
636
639static void
640usb_moded_config_get_cb(umdbus_context_t *context)
641{
642 LOG_REGISTER_CONTEXT;
643
644 uid_t uid = umdbus_get_sender_uid(context->sender);
645 char *config = config_get_mode_setting(uid);
646
647 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
648 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
649 g_free(config);
650}
651
652/* ------------------------------------------------------------------------- *
653 * supported modes -- modes that exist and are not hidden
654 * ------------------------------------------------------------------------- */
655
658static void
659usb_moded_mode_list_cb(umdbus_context_t *context)
660{
661 LOG_REGISTER_CONTEXT;
662
663 gchar *mode_list = common_get_mode_list(SUPPORTED_MODES_LIST, 0);
664
665 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
666 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &mode_list, DBUS_TYPE_INVALID);
667 g_free(mode_list);
668}
669
670/* ------------------------------------------------------------------------- *
671 * available modes -- modes that exist and are whitelisted and not hidden
672 * ------------------------------------------------------------------------- */
673
676static void
677usb_moded_available_modes_get_cb(umdbus_context_t *context)
678{
679 LOG_REGISTER_CONTEXT;
680
681 gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST, 0);
682
683 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
684 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &mode_list, DBUS_TYPE_INVALID);
685 g_free(mode_list);
686}
687
690static void
691usb_moded_available_modes_for_user_cb(umdbus_context_t *context)
692{
693 LOG_REGISTER_CONTEXT;
694
695 uid_t uid = umdbus_get_sender_uid(context->sender);
696 gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST, uid);
697
698 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
699 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &mode_list, DBUS_TYPE_INVALID);
700 g_free(mode_list);
701}
702
703/* ------------------------------------------------------------------------- *
704 * hidden modes -- one layer of masking modes from settings ui
705 * ------------------------------------------------------------------------- */
706
709static void
710usb_moded_mode_hide_cb(umdbus_context_t *context)
711{
712 LOG_REGISTER_CONTEXT;
713
714 char *config = 0;
715 DBusError err = DBUS_ERROR_INIT;
716
717 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID) ) {
718 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
719 }
720#ifdef SAILFISH_ACCESS_CONTROL
721 /* do not let non-owner user hide modes */
722 else if( !sailfish_access_control_hasgroup(umdbus_get_sender_uid(context->sender), "sailfish-system") ) {
723 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_ACCESS_DENIED, context->member);
724 }
725#endif
726 else {
727 /* error checking is done when setting configuration */
728 int ret = config_set_hide_mode_setting(config);
729 if( SET_CONFIG_OK(ret) ) {
730 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
731 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
732 }
733 else {
734 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, config);
735 }
736 }
737 dbus_error_free(&err);
738}
739
742static void
743usb_moded_mode_unhide_cb(umdbus_context_t *context)
744{
745 LOG_REGISTER_CONTEXT;
746
747 char *config = 0;
748 DBusError err = DBUS_ERROR_INIT;
749
750 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID) ) {
751 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
752 }
753#ifdef SAILFISH_ACCESS_CONTROL
754 /* do not let non-owner user unhide modes */
755 else if( !sailfish_access_control_hasgroup(umdbus_get_sender_uid(context->sender), "sailfish-system") ) {
756 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_ACCESS_DENIED, context->member);
757 }
758#endif
759 else {
760 /* error checking is done when setting configuration */
761 int ret = config_set_unhide_mode_setting(config);
762 if( SET_CONFIG_OK(ret) ) {
763 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
764 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
765 }
766 else {
767 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, config);
768 }
769 }
770 dbus_error_free(&err);
771}
772
775static void
776usb_moded_hidden_get_cb(umdbus_context_t *context)
777{
778 LOG_REGISTER_CONTEXT;
779
780 char *config = config_get_hidden_modes();
781 if( !config )
782 config = g_strdup("");
783 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
784 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
785 g_free(config);
786}
787
788/* ------------------------------------------------------------------------- *
789 * whitelisted modes -- another layer of masking modes from settings ui
790 * ------------------------------------------------------------------------- */
791
794static void
795usb_moded_whitelisted_modes_get_cb(umdbus_context_t *context)
796{
797 LOG_REGISTER_CONTEXT;
798
799 gchar *mode_list = config_get_mode_whitelist();
800
801 if( !mode_list )
802 mode_list = g_strdup("");
803
804 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
805 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &mode_list, DBUS_TYPE_INVALID);
806 g_free(mode_list);
807}
808
811static void
812usb_moded_whitelisted_modes_set_cb(umdbus_context_t *context)
813{
814 LOG_REGISTER_CONTEXT;
815
816 const char *whitelist = 0;
817 DBusError err = DBUS_ERROR_INIT;
818
819 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_STRING, &whitelist, DBUS_TYPE_INVALID) ) {
820 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
821 }
822 else {
823 int ret = config_set_mode_whitelist(whitelist);
824 if( SET_CONFIG_OK(ret) ) {
825 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
826 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &whitelist, DBUS_TYPE_INVALID);
827 }
828 else
829 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, whitelist);
830 }
831 dbus_error_free(&err);
832}
833
836static void
837usb_moded_user_config_clear_cb(umdbus_context_t *context)
838{
839 LOG_REGISTER_CONTEXT;
840
841 dbus_uint32_t uid = 0;
842 DBusError err = DBUS_ERROR_INIT;
843
844 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID) ) {
845 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
846 }
847 else {
848 if ( !config_user_clear(uid) )
849 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
850 else if( (context->rsp = dbus_message_new_method_return(context->msg)) )
851 dbus_message_append_args(context->rsp, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID);
852 }
853 dbus_error_free(&err);
854}
855
858static void
859usb_moded_whitelisted_set_cb(umdbus_context_t *context)
860{
861 LOG_REGISTER_CONTEXT;
862
863 const char *mode = 0;
864 dbus_bool_t enabled = FALSE;
865 DBusError err = DBUS_ERROR_INIT;
866
867 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_STRING, &mode, DBUS_TYPE_BOOLEAN, &enabled, DBUS_TYPE_INVALID) )
868 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
869 else {
870 int ret = config_set_mode_in_whitelist(mode, enabled);
871 if( SET_CONFIG_OK(ret) )
872 context->rsp = dbus_message_new_method_return(context->msg);
873 else
874 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, mode);
875 }
876 dbus_error_free(&err);
877}
878
879/* ------------------------------------------------------------------------- *
880 * network configuration
881 * ------------------------------------------------------------------------- */
882
885static void
886usb_moded_network_set_cb(umdbus_context_t *context)
887{
888 LOG_REGISTER_CONTEXT;
889
890 char *config = 0;
891 char *setting = 0;
892 DBusError err = DBUS_ERROR_INIT;
893
894 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_STRING, &setting, DBUS_TYPE_INVALID) ) {
895 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
896 }
897 else {
898 /* error checking is done when setting configuration */
899 int ret = config_set_network_setting(config, setting);
900 if( SET_CONFIG_OK(ret) ) {
901 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
902 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &config, DBUS_TYPE_STRING, &setting, DBUS_TYPE_INVALID);
904 }
905 else {
906 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, config);
907 }
908 }
909 dbus_error_free(&err);
910}
911
914static void
915usb_moded_network_get_cb(umdbus_context_t *context)
916{
917 LOG_REGISTER_CONTEXT;
918
919 char *config = 0;
920 char *setting = 0;
921 DBusError err = DBUS_ERROR_INIT;
922
923 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID) ) {
924 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
925 }
926 else {
927 setting = config_get_network_setting(config);
928 if( setting ) {
929 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
930 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &config, DBUS_TYPE_STRING, &setting, DBUS_TYPE_INVALID);
931 free(setting);
932 }
933 else {
934 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, config);
935 }
936 }
937 dbus_error_free(&err);
938}
939
940/* ------------------------------------------------------------------------- *
941 * miscellaneous
942 * ------------------------------------------------------------------------- */
943
946static void
947usb_moded_rescue_off_cb(umdbus_context_t *context)
948{
949 LOG_REGISTER_CONTEXT;
950
951 usbmoded_set_rescue_mode(false);
952 log_debug("Rescue mode off\n ");
953 context->rsp = dbus_message_new_method_return(context->msg);
954}
955
956static const member_info_t usb_moded_members[] =
957{
958 ADD_METHOD(USB_MODE_STATE_REQUEST,
959 usb_moded_state_request_cb,
960 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
961 ADD_METHOD(USB_MODE_TARGET_STATE_GET,
962 usb_moded_target_state_get_cb,
963 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
964 ADD_METHOD(USB_MODE_TARGET_CONFIG_GET,
965 usb_moded_target_config_get_cb,
966 " <arg name=\"config\" type=\"a{sv}\" direction=\"out\"/>\n"
967 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QVariantMap\"/>\n"),
968 ADD_METHOD(USB_MODE_STATE_SET,
969 usb_moded_state_set_cb,
970 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
971 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
972 ADD_METHOD(USB_MODE_CONFIG_SET,
973 usb_moded_config_set_cb,
974 " <arg name=\"config\" type=\"s\" direction=\"in\"/>\n"
975 " <arg name=\"config\" type=\"s\" direction=\"out\"/>\n"),
976 ADD_METHOD(USB_MODE_CONFIG_GET,
977 usb_moded_config_get_cb,
978 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
979 ADD_METHOD(USB_MODE_LIST,
980 usb_moded_mode_list_cb,
981 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
982 ADD_METHOD(USB_MODE_AVAILABLE_MODES_GET,
983 usb_moded_available_modes_get_cb,
984 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
985 ADD_METHOD(USB_MODE_AVAILABLE_MODES_FOR_USER,
986 usb_moded_available_modes_for_user_cb,
987 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
988 ADD_METHOD(USB_MODE_HIDE,
989 usb_moded_mode_hide_cb,
990 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
991 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
992 ADD_METHOD(USB_MODE_UNHIDE,
993 usb_moded_mode_unhide_cb,
994 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
995 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
996 ADD_METHOD(USB_MODE_HIDDEN_GET,
997 usb_moded_hidden_get_cb,
998 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
999 ADD_METHOD(USB_MODE_WHITELISTED_MODES_GET,
1000 usb_moded_whitelisted_modes_get_cb,
1001 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
1002 ADD_METHOD(USB_MODE_WHITELISTED_MODES_SET,
1003 usb_moded_whitelisted_modes_set_cb,
1004 " <arg name=\"modes\" type=\"s\" direction=\"in\"/>\n"),
1005 ADD_METHOD(USB_MODE_WHITELISTED_SET,
1006 usb_moded_whitelisted_set_cb,
1007 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
1008 " <arg name=\"whitelisted\" type=\"b\" direction=\"in\"/>\n"),
1009 ADD_METHOD(USB_MODE_NETWORK_SET,
1010 usb_moded_network_set_cb,
1011 " <arg name=\"key\" type=\"s\" direction=\"in\"/>\n"
1012 " <arg name=\"value\" type=\"s\" direction=\"in\"/>\n"
1013 " <arg name=\"key\" type=\"s\" direction=\"out\"/>\n"
1014 " <arg name=\"value\" type=\"s\" direction=\"out\"/>\n"),
1015 ADD_METHOD(USB_MODE_NETWORK_GET,
1016 usb_moded_network_get_cb,
1017 " <arg name=\"key\" type=\"s\" direction=\"in\"/>\n"
1018 " <arg name=\"key\" type=\"s\" direction=\"out\"/>\n"
1019 " <arg name=\"value\" type=\"s\" direction=\"out\"/>\n"),
1020 ADD_METHOD(USB_MODE_RESCUE_OFF,
1021 usb_moded_rescue_off_cb,
1022 0),
1023 ADD_METHOD(USB_MODE_USER_CONFIG_CLEAR,
1024 usb_moded_user_config_clear_cb,
1025 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"),
1027 " <arg name=\"mode_or_event\" type=\"s\"/>\n"),
1028 ADD_SIGNAL(USB_MODE_CURRENT_STATE_SIGNAL_NAME,
1029 " <arg name=\"mode\" type=\"s\"/>\n"),
1030 ADD_SIGNAL(USB_MODE_TARGET_STATE_SIGNAL_NAME,
1031 " <arg name=\"mode\" type=\"s\"/>\n"),
1032 ADD_SIGNAL(USB_MODE_TARGET_CONFIG_SIGNAL_NAME,
1033 " <arg name=\"config\" type=\"a{sv}\"/>\n"
1034 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.In0\" value=\"QVariantMap\"/>\n"),
1035 ADD_SIGNAL(USB_MODE_EVENT_SIGNAL_NAME,
1036 " <arg name=\"event\" type=\"s\"/>\n"),
1037 ADD_SIGNAL(USB_MODE_CONFIG_SIGNAL_NAME,
1038 " <arg name=\"section\" type=\"s\"/>\n"
1039 " <arg name=\"key\" type=\"s\"/>\n"
1040 " <arg name=\"value\" type=\"s\"/>\n"),
1041 ADD_SIGNAL(USB_MODE_SUPPORTED_MODES_SIGNAL_NAME,
1042 " <arg name=\"modes\" type=\"s\"/>\n"),
1043 ADD_SIGNAL(USB_MODE_AVAILABLE_MODES_SIGNAL_NAME,
1044 " <arg name=\"modes\" type=\"s\"/>\n"),
1045 ADD_SIGNAL(USB_MODE_HIDDEN_MODES_SIGNAL_NAME,
1046 " <arg name=\"modes\" type=\"s\"/>\n"),
1047 ADD_SIGNAL(USB_MODE_WHITELISTED_MODES_SIGNAL_NAME,
1048 " <arg name=\"modes\" type=\"s\"/>\n"),
1049 ADD_SIGNAL(USB_MODE_ERROR_SIGNAL_NAME,
1050 " <arg name=\"error\" type=\"s\"/>\n"),
1052};
1053
1054static const interface_info_t usb_moded_interface = {
1055 .interface = USB_MODE_INTERFACE,
1056 .members = usb_moded_members
1057};
1058
1059/* ========================================================================= *
1060 * Functions
1061 * ========================================================================= */
1062
1065static const interface_info_t *standard_interfaces[] = {
1066 &introspectable_interface,
1067 &peer_interface,
1068 0
1069};
1070
1073static const interface_info_t *usb_moded_interfaces[] = {
1074 &introspectable_interface,
1075 &peer_interface,
1076 &usb_moded_interface,
1077 0
1078};
1079
1082static const object_info_t usb_moded_objects[] =
1083{
1084 /* NOTE: Parents must be listed before children.
1085 * See object_info_introspect().
1086 */
1087 {
1088 .object = "/",
1089 .interfaces = standard_interfaces,
1090 },
1091 {
1092 .object = "/com",
1093 .interfaces = standard_interfaces,
1094 },
1095 {
1096 .object = "/com/meego",
1097 .interfaces = standard_interfaces,
1098 },
1099 {
1100 .object = USB_MODE_OBJECT, // = "/com/meego/usb_moded"
1101 .interfaces = usb_moded_interfaces,
1102 },
1103 {
1104 .object = 0
1105 },
1106};
1107
1110static const object_info_t *
1111umdbus_get_object_info(const char *object)
1112{
1113 LOG_REGISTER_CONTEXT;
1114
1115 const object_info_t *obj = 0;
1116
1117 if( !object )
1118 goto EXIT;
1119
1120 for( size_t i = 0; usb_moded_objects[i].object; ++i ) {
1121 if( !strcmp(usb_moded_objects[i].object, object) ) {
1122 obj = &usb_moded_objects[i];
1123 break;
1124 }
1125 }
1126
1127EXIT:
1128 return obj;
1129}
1130
1135void
1137{
1138 LOG_REGISTER_CONTEXT;
1139
1140 const object_info_t *object_info = umdbus_get_object_info(USB_MODE_OBJECT);
1141 char *xml = object_info_get_introspect_xml(object_info, USB_MODE_INTERFACE);
1142 fprintf(stdout, "%s", xml ?: "\n");
1143 free(xml);
1144};
1145
1150void
1152{
1153 LOG_REGISTER_CONTEXT;
1154
1155 static const char dtd[] =
1156 "<!DOCTYPE busconfig PUBLIC\n"
1157 " \"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN\"\n"
1158 " \"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\">\n";
1159
1160 fprintf(stdout, "%s\n", dtd);
1161 fprintf(stdout, "<busconfig>\n");
1162
1163 fprintf(stdout,
1164 " <policy user=\"root\">\n"
1165 " <allow own=\"" USB_MODE_SERVICE "\"/>\n"
1166 " <allow send_destination=\"" USB_MODE_SERVICE "\"\n"
1167 " send_interface=\"" USB_MODE_INTERFACE "\"/>\n"
1168 " </policy>\n");
1169
1170 fprintf(stdout,
1171 " <policy context=\"default\">\n"
1172 " <deny own=\"" USB_MODE_SERVICE "\"/>\n"
1173 " <deny send_destination=\"" USB_MODE_SERVICE "\"\n"
1174 " send_interface=\"" USB_MODE_INTERFACE "\"/>\n"
1175 " <allow send_destination=\"" USB_MODE_SERVICE "\"\n"
1176 " send_interface=\"org.freedesktop.DBus.Introspectable\"/>\n");
1177
1178 for( const member_info_t *mem = usb_moded_members; mem->member; ++mem ) {
1179 if( mem->type != DBUS_MESSAGE_TYPE_METHOD_CALL )
1180 continue;
1181 fprintf(stdout,
1182 " <allow send_destination=\"" USB_MODE_SERVICE "\"\n"
1183 " send_interface=\"" USB_MODE_INTERFACE "\"\n"
1184 " send_member=\"%s\"/>\n",
1185 mem->member);
1186 }
1187 fprintf(stdout, " </policy>\n");
1188 fprintf(stdout, "</busconfig>\n");
1189}
1190
1194void umdbus_send_config_signal(const char *section, const char *key, const char *value)
1195{
1196 LOG_REGISTER_CONTEXT;
1197
1198 DBusMessage* msg = 0;
1199
1200 if( !section || !key || !value ) {
1201 log_err("config notification with NULL %s",
1202 !section ? "section" : !key ? "key" : value);
1203 goto EXIT;
1204 }
1205
1206 if( !umdbus_service_name_acquired ) {
1207 log_err("config notification without service: [%s] %s=%s",
1208 section, key, value);
1209 goto EXIT;
1210 }
1211
1212 if( !umdbus_connection ) {
1213 log_err("config notification without connection: [%s] %s=%s",
1214 section, key, value);
1215 goto EXIT;
1216 }
1217
1218 log_debug("broadcast signal %s(%s, %s, %s)\n", USB_MODE_CONFIG_SIGNAL_NAME, section, key, value);
1219
1220 msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE, USB_MODE_CONFIG_SIGNAL_NAME);
1221 if( !msg )
1222 goto EXIT;
1223
1224 dbus_message_append_args(msg, DBUS_TYPE_STRING, &section,
1225 DBUS_TYPE_STRING, &key,
1226 DBUS_TYPE_STRING, &value,
1227 DBUS_TYPE_INVALID);
1228 dbus_connection_send(umdbus_connection, msg, NULL);
1229
1230EXIT:
1231 if( msg )
1232 dbus_message_unref(msg);
1233}
1234
1235static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data)
1236{
1237 (void)user_data;
1238
1239 LOG_REGISTER_CONTEXT;
1240
1241 DBusHandlerResult status = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1242
1243 umdbus_context_t context = { .msg = msg, };
1244
1245 /* We are only interested in signals and method calls */
1246 switch( (context.type = dbus_message_get_type(msg)) ) {
1247 case DBUS_MESSAGE_TYPE_SIGNAL:
1248 case DBUS_MESSAGE_TYPE_METHOD_CALL:
1249 break;
1250 default:
1251 goto EXIT;
1252 }
1253
1254 /* Parse message basic info */
1255 if( !(context.sender = dbus_message_get_sender(msg)) )
1256 goto EXIT;
1257
1258 if( !(context.object = dbus_message_get_path(msg)) )
1259 goto EXIT;
1260
1261 if( !(context.interface = dbus_message_get_interface(msg)) )
1262 goto EXIT;
1263
1264 if( !(context.member = dbus_message_get_member(msg)) )
1265 goto EXIT;
1266
1267 log_debug("DBUS %s %s.%s from %s",
1268 dbus_message_type_to_string(context.type),
1269 context.interface, context.member, context.sender);
1270
1271 /* Deal with incoming signals */
1272 if( context.type == DBUS_MESSAGE_TYPE_SIGNAL ) {
1273 if( !strcmp(context.interface, INIT_DONE_INTERFACE) && !strcmp(context.member, INIT_DONE_SIGNAL) ) {
1274 /* Update the cached state value */
1276 }
1277 goto EXIT;
1278 }
1279
1280 /* Locate and use method call handler */
1281 context.object_info = umdbus_get_object_info(context.object);
1282 context.interface_info = object_info_get_interface(context.object_info,
1283 context.interface);
1284 context.member_info = interface_info_get_member(context.interface_info,
1285 context.member);
1286
1287 if( context.member_info && context.member_info->type == context.type ) {
1288 if( context.member_info->handler )
1289 context.member_info->handler(&context);
1290 }
1291 else if( !context.object_info ) {
1292 context.rsp = dbus_message_new_error_printf(context.msg,
1293 DBUS_ERROR_UNKNOWN_OBJECT,
1294 "Object '%s' does not exist",
1295 context.object);
1296 }
1297 else if( !context.interface_info ) {
1298 context.rsp = dbus_message_new_error_printf(context.msg,
1299 DBUS_ERROR_UNKNOWN_INTERFACE,
1300 "Interface '%s' does not exist",
1301 context.interface);
1302 }
1303 else {
1304 context.rsp = dbus_message_new_error_printf(context.msg,
1305 DBUS_ERROR_UNKNOWN_METHOD,
1306 "Method '%s.%s' does not exist",
1307 context.interface,
1308 context.member);
1309 }
1310
1311EXIT:
1312 if( context.rsp ) {
1313 status = DBUS_HANDLER_RESULT_HANDLED;
1314 if( !dbus_message_get_no_reply(context.msg) ) {
1315 if( !dbus_connection_send(connection, context.rsp, 0) )
1316 log_debug("Failed sending reply. Out Of Memory!\n");
1317 }
1318 dbus_message_unref(context.rsp);
1319 }
1320
1321 return status;
1322}
1323
1324DBusConnection *umdbus_get_connection(void)
1325{
1326 LOG_REGISTER_CONTEXT;
1327
1328 DBusConnection *connection = 0;
1329 if( umdbus_connection )
1330 connection = dbus_connection_ref(umdbus_connection);
1331 else
1332 log_err("something asked for connection ref while unconnected");
1333 return connection;
1334}
1335
1342{
1343 LOG_REGISTER_CONTEXT;
1344
1345 gboolean status = FALSE;
1346 DBusError error = DBUS_ERROR_INIT;
1347
1348 /* connect to system bus */
1349 if ((umdbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL)
1350 {
1351 log_debug("Failed to open connection to system message bus; %s\n", error.message);
1352 goto EXIT;
1353 }
1354
1355 /* Initialise message handlers */
1356 if (!dbus_connection_add_filter(umdbus_connection, umdbus_msg_handler, NULL, NULL))
1357 goto EXIT;
1358
1359 /* Listen to init-done signals */
1360 dbus_bus_add_match(umdbus_connection, INIT_DONE_MATCH, 0);
1361
1362 /* Re-check flag file after adding signal listener */
1364
1365 /* Connect D-Bus to the mainloop */
1366 dbus_gmain_set_up_connection(umdbus_connection, NULL);
1367
1368 /* everything went fine */
1369 status = TRUE;
1370
1371EXIT:
1372 dbus_error_free(&error);
1373 return status;
1374}
1375
1382{
1383 LOG_REGISTER_CONTEXT;
1384
1385 gboolean status = FALSE;
1386 DBusError error = DBUS_ERROR_INIT;
1387 int ret;
1388
1389 if( !umdbus_connection ) {
1390 goto EXIT;
1391 }
1392
1393 /* Acquire D-Bus service */
1394 ret = dbus_bus_request_name(umdbus_connection, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
1395 if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
1396 {
1397 log_debug("failed claiming dbus name\n");
1398 if( dbus_error_is_set(&error) )
1399 log_debug("DBUS ERROR: %s, %s", error.name, error.message);
1400 goto EXIT;
1401 }
1402 log_debug("claimed name %s", USB_MODE_SERVICE);
1403 umdbus_service_name_acquired = TRUE;
1404 /* everything went fine */
1405 status = TRUE;
1406
1407EXIT:
1408 dbus_error_free(&error);
1409 return status;
1410}
1411
1414static void umdbus_cleanup_service(void)
1415{
1416 LOG_REGISTER_CONTEXT;
1417
1418 if( !umdbus_service_name_acquired )
1419 goto EXIT;
1420
1421 umdbus_service_name_acquired = FALSE;
1422 log_debug("release name %s", USB_MODE_SERVICE);
1423
1424 if( umdbus_connection &&
1425 dbus_connection_get_is_connected(umdbus_connection) )
1426 {
1427 dbus_bus_release_name(umdbus_connection, USB_MODE_SERVICE, NULL);
1428 }
1429
1430EXIT:
1431 return;
1432}
1433
1439{
1440 LOG_REGISTER_CONTEXT;
1441
1442 /* clean up system bus connection */
1443 if (umdbus_connection != NULL)
1444 {
1445 umdbus_cleanup_service();
1446
1447 dbus_connection_remove_filter(umdbus_connection, umdbus_msg_handler, NULL);
1448
1449 dbus_connection_unref(umdbus_connection),
1450 umdbus_connection = NULL;
1451 }
1452}
1453
1460static DBusMessage*
1461umdbus_new_signal(const char *signal_name)
1462{
1463 LOG_REGISTER_CONTEXT;
1464
1465 DBusMessage *msg = 0;
1466
1467 if( !umdbus_connection )
1468 {
1469 log_err("sending signal %s without dbus connection", signal_name);
1470 goto EXIT;
1471 }
1472 if( !umdbus_service_name_acquired )
1473 {
1474 log_err("sending signal %s before acquiring name", signal_name);
1475 goto EXIT;
1476 }
1477 // create a signal and check for errors
1478 msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE,
1479 signal_name );
1480 if( !msg )
1481 {
1482 log_err("allocating signal %s failed", signal_name);
1483 goto EXIT;
1484 }
1485
1486EXIT:
1487 return msg;
1488}
1489
1498static int
1499umdbus_send_signal_ex(const char *signal_name, const char *content)
1500{
1501 LOG_REGISTER_CONTEXT;
1502
1503 int result = 1;
1504 DBusMessage* msg = 0;
1505
1506 /* Assume NULL content equals no value / empty list, and that skipping
1507 * signal broadcast is never preferable over sending empty string. */
1508 if( !content )
1509 content = "";
1510
1511 log_debug("broadcast signal %s(%s)", signal_name, content);
1512
1513 if( !(msg = umdbus_new_signal(signal_name)) )
1514 goto EXIT;
1515
1516 // append arguments onto signal
1517 if( !dbus_message_append_args(msg,
1518 DBUS_TYPE_STRING, &content,
1519 DBUS_TYPE_INVALID) )
1520 {
1521 log_err("appending arguments to signal %s failed", signal_name);
1522 goto EXIT;
1523 }
1524
1525 // send the message on the correct bus
1526 if( !dbus_connection_send(umdbus_connection, msg, 0) )
1527 {
1528 log_err("sending signal %s failed", signal_name);
1529 goto EXIT;
1530 }
1531 result = 0;
1532
1533EXIT:
1534 // free the message
1535 if(msg != 0)
1536 dbus_message_unref(msg);
1537
1538 return result;
1539}
1540
1548static void umdbus_send_legacy_signal(const char *state_ind)
1549{
1550 LOG_REGISTER_CONTEXT;
1551
1552 umdbus_send_signal_ex(USB_MODE_SIGNAL_NAME, state_ind);
1553}
1554
1559void umdbus_send_current_state_signal(const char *state_ind)
1560{
1561 LOG_REGISTER_CONTEXT;
1562
1563 umdbus_send_signal_ex(USB_MODE_CURRENT_STATE_SIGNAL_NAME,
1564 state_ind);
1565 umdbus_send_legacy_signal(state_ind);
1566}
1567
1577static bool
1578umdbus_append_basic_entry(DBusMessageIter *iter, const char *key,
1579 int type, const void *val)
1580{
1581 LOG_REGISTER_CONTEXT;
1582
1583 /* Signature must be provided for variant containers */
1584 const char *signature = 0;
1585 switch( type ) {
1586 case DBUS_TYPE_INT32: signature = DBUS_TYPE_INT32_AS_STRING; break;
1587 case DBUS_TYPE_STRING: signature = DBUS_TYPE_STRING_AS_STRING; break;
1588 default: break;
1589 }
1590 if( !signature ) {
1591 log_err("unhandled D-Bus type: %d", type);
1592 goto bailout_message;
1593 }
1594
1595 DBusMessageIter entry, variant;
1596
1597 if( !dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
1598 0, &entry) )
1599 goto bailout_message;
1600
1601 if( !dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key) )
1602 goto bailout_entry;
1603
1604 if( !dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1605 signature, &variant) )
1606 goto bailout_entry;
1607
1608 if( !dbus_message_iter_append_basic(&variant, type, val) )
1609 goto bailout_variant;
1610
1611 if( !dbus_message_iter_close_container(&entry, &variant) )
1612 goto bailout_variant;
1613
1614 if( !dbus_message_iter_close_container(iter, &entry) )
1615 goto bailout_entry;
1616
1617 return true;
1618
1619bailout_variant:
1620 dbus_message_iter_abandon_container(&entry, &variant);
1621
1622bailout_entry:
1623 dbus_message_iter_abandon_container(iter, &entry);
1624
1625bailout_message:
1626 return false;
1627}
1628
1637static bool
1638umdbus_append_int32_entry(DBusMessageIter *iter, const char *key, int val)
1639{
1640 LOG_REGISTER_CONTEXT;
1641
1642 dbus_int32_t arg = val;
1643 return umdbus_append_basic_entry(iter, key, DBUS_TYPE_INT32, &arg);
1644}
1645
1654static bool
1655umdbus_append_string_entry(DBusMessageIter *iter, const char *key,
1656 const char *val)
1657{
1658 LOG_REGISTER_CONTEXT;
1659
1660 if( !val )
1661 val = "";
1662 return umdbus_append_basic_entry(iter, key, DBUS_TYPE_STRING, &val);
1663}
1664
1672static bool
1673umdbus_append_mode_details(DBusMessage *msg, const char *mode_name)
1674{
1675 LOG_REGISTER_CONTEXT;
1676
1677 const modedata_t *data = usbmoded_get_modedata(mode_name);
1678
1679 DBusMessageIter body, dict;
1680
1681 dbus_message_iter_init_append(msg, &body);
1682
1683 if( !dbus_message_iter_open_container(&body,
1684 DBUS_TYPE_ARRAY,
1685 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1686 DBUS_TYPE_STRING_AS_STRING
1687 DBUS_TYPE_VARIANT_AS_STRING
1688 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1689 &dict) )
1690 goto bailout_message;
1691
1692 /* Note: mode_name is special case: It needs to be valid even
1693 * if the mode does not have dynamic configuration.
1694 */
1695 if( !umdbus_append_string_entry(&dict, "mode_name", mode_name) )
1696 goto bailout_dict;
1697
1698 /* For the rest of the mode attrs we use fallback data if there
1699 * is no dynamic config / dynamic config does not define some value.
1700 */
1701
1702#define ADD_STR(name) \
1703 if( !umdbus_append_string_entry(&dict, #name, data ? data->name : 0) )\
1704 goto bailout_dict;
1705#define ADD_INT(name) \
1706 if( !umdbus_append_int32_entry(&dict, #name, data ? data->name : 0) )\
1707 goto bailout_dict;
1708
1709 /* Attributes that we presume to be needed */
1710 ADD_INT(appsync);
1711 ADD_INT(network);
1712 ADD_STR(network_interface);
1713 ADD_INT(nat);
1714 ADD_INT(dhcp_server);
1715#ifdef CONNMAN
1716 ADD_STR(connman_tethering);
1717#endif
1718
1719 /* Attributes that are not exposed for now */
1720#if 0
1721 ADD_INT(mass_storage);
1722 ADD_STR(mode_module);
1723 ADD_STR(sysfs_path);
1724 ADD_STR(sysfs_value);
1725 ADD_STR(sysfs_reset_value);
1726 ADD_STR(android_extra_sysfs_path);
1727 ADD_STR(android_extra_sysfs_value);
1728 ADD_STR(android_extra_sysfs_path2);
1729 ADD_STR(android_extra_sysfs_value2);
1730 ADD_STR(android_extra_sysfs_path3);
1731 ADD_STR(android_extra_sysfs_value3);
1732 ADD_STR(android_extra_sysfs_path4);
1733 ADD_STR(android_extra_sysfs_value4);
1734 ADD_STR(idProduct);
1735 ADD_STR(idVendorOverride);
1736#endif
1737
1738#undef ADD_STR
1739#undef ADD_INT
1740
1741 if( !dbus_message_iter_close_container(&body, &dict) )
1742 goto bailout_dict;
1743
1744 return true;
1745
1746bailout_dict:
1747 dbus_message_iter_abandon_container(&body, &dict);
1748
1749bailout_message:
1750 return false;
1751}
1752
1757static void
1758umdbus_send_mode_details_signal(const char *mode_name)
1759{
1760 DBusMessage* msg = 0;
1761
1762 if( !(msg = umdbus_new_signal(USB_MODE_TARGET_CONFIG_SIGNAL_NAME)) )
1763 goto EXIT;
1764
1765 if( !umdbus_append_mode_details(msg, mode_name) )
1766 goto EXIT;
1767
1768 dbus_connection_send(umdbus_connection, msg, 0);
1769
1770EXIT:
1771 if(msg != 0)
1772 dbus_message_unref(msg);
1773}
1774
1779void umdbus_send_target_state_signal(const char *state_ind)
1780{
1781 LOG_REGISTER_CONTEXT;
1782
1783 /* Send target mode details before claiming intent to
1784 * do mode transition. This way the clients tracking
1785 * configuration changes can assume they have valid
1786 * details immediately when transition begins.
1787 *
1788 * If clients for any reason need to pay closer attention
1789 * to signal timing, the mode_name contained in this broadcast
1790 * can be checked against current / target mode.
1791 */
1792 umdbus_send_mode_details_signal(state_ind);
1793
1794 umdbus_send_signal_ex(USB_MODE_TARGET_STATE_SIGNAL_NAME,
1795 state_ind);
1796}
1797
1802void umdbus_send_event_signal(const char *state_ind)
1803{
1804 LOG_REGISTER_CONTEXT;
1805
1806 umdbus_send_signal_ex(USB_MODE_EVENT_SIGNAL_NAME,
1807 state_ind);
1808 umdbus_send_legacy_signal(state_ind);
1809}
1810
1818int umdbus_send_error_signal(const char *error)
1819{
1820 LOG_REGISTER_CONTEXT;
1821
1822 return umdbus_send_signal_ex(USB_MODE_ERROR_SIGNAL_NAME, error);
1823}
1824
1832int umdbus_send_supported_modes_signal(const char *supported_modes)
1833{
1834 LOG_REGISTER_CONTEXT;
1835
1836 return umdbus_send_signal_ex(USB_MODE_SUPPORTED_MODES_SIGNAL_NAME, supported_modes);
1837}
1838
1846int umdbus_send_available_modes_signal(const char *available_modes)
1847{
1848 LOG_REGISTER_CONTEXT;
1849
1850 return umdbus_send_signal_ex(USB_MODE_AVAILABLE_MODES_SIGNAL_NAME, available_modes);
1851}
1852
1860int umdbus_send_hidden_modes_signal(const char *hidden_modes)
1861{
1862 LOG_REGISTER_CONTEXT;
1863
1864 return umdbus_send_signal_ex(USB_MODE_HIDDEN_MODES_SIGNAL_NAME, hidden_modes);
1865}
1866
1874{
1875 LOG_REGISTER_CONTEXT;
1876
1877 return umdbus_send_signal_ex(USB_MODE_WHITELISTED_MODES_SIGNAL_NAME, whitelist);
1878}
1879
1885static void umdbus_get_name_owner_cb(DBusPendingCall *pc, void *aptr)
1886{
1887 LOG_REGISTER_CONTEXT;
1888
1889 usb_moded_get_name_owner_fn cb = aptr;
1890
1891 DBusMessage *rsp = 0;
1892 const char *dta = 0;
1893 DBusError err = DBUS_ERROR_INIT;
1894
1895 if( !(rsp = dbus_pending_call_steal_reply(pc)) ) {
1896 log_err("did not get reply");
1897 goto EXIT;
1898 }
1899
1900 if( dbus_set_error_from_message(&err, rsp) )
1901 {
1902 if( strcmp(err.name, DBUS_ERROR_NAME_HAS_NO_OWNER) )
1903 log_err("error reply: %s: %s", err.name, err.message);
1904 goto EXIT;
1905 }
1906
1907 if( !dbus_message_get_args(rsp, &err,
1908 DBUS_TYPE_STRING, &dta,
1909 DBUS_TYPE_INVALID) )
1910 {
1911 if( strcmp(err.name, DBUS_ERROR_NAME_HAS_NO_OWNER) )
1912 log_err("parse error: %s: %s", err.name, err.message);
1913 goto EXIT;
1914 }
1915
1916EXIT:
1917 /* Allways call the notification function. Equate any error
1918 * situations with "service does not have an owner". */
1919 cb(dta ?: "");
1920
1921 if( rsp ) dbus_message_unref(rsp);
1922
1923 dbus_error_free(&err);
1924}
1925
1934gboolean umdbus_get_name_owner_async(const char *name,
1935 usb_moded_get_name_owner_fn cb,
1936 DBusPendingCall **ppc)
1937{
1938 LOG_REGISTER_CONTEXT;
1939
1940 gboolean ack = FALSE;
1941 DBusMessage *req = 0;
1942 DBusPendingCall *pc = 0;
1943
1944 if(!umdbus_connection)
1945 goto EXIT;
1946
1947 req = dbus_message_new_method_call(DBUS_INTERFACE_DBUS,
1948 DBUS_PATH_DBUS,
1949 DBUS_INTERFACE_DBUS,
1951 if( !req ) {
1952 log_err("could not create method call message");
1953 goto EXIT;
1954 }
1955
1956 if( !dbus_message_append_args(req,
1957 DBUS_TYPE_STRING, &name,
1958 DBUS_TYPE_INVALID) ) {
1959 log_err("could not add method call parameters");
1960 goto EXIT;
1961 }
1962
1963 if( !dbus_connection_send_with_reply(umdbus_connection, req, &pc, -1) )
1964 goto EXIT;
1965
1966 if( !pc )
1967 goto EXIT;
1968
1969 if( !dbus_pending_call_set_notify(pc, umdbus_get_name_owner_cb, cb, 0) )
1970 goto EXIT;
1971
1972 ack = TRUE;
1973
1974 if( ppc )
1975 *ppc = pc, pc = 0;
1976
1977EXIT:
1978
1979 if( pc ) dbus_pending_call_unref(pc);
1980 if( req ) dbus_message_unref(req);
1981
1982 return ack;
1983}
1984
1991static uid_t
1992umdbus_get_sender_uid(const char *name)
1993{
1994 LOG_REGISTER_CONTEXT;
1995
1996 pid_t pid = PID_UNKNOWN;
1997 uid_t uid = UID_UNKNOWN;
1998 DBusMessage *req = 0;
1999 DBusMessage *rsp = 0;
2000 DBusError err = DBUS_ERROR_INIT;
2001 char path[256];
2002 struct stat st;
2003
2004 if(!umdbus_connection)
2005 goto EXIT;
2006
2007 req = dbus_message_new_method_call(DBUS_INTERFACE_DBUS,
2008 DBUS_PATH_DBUS,
2009 DBUS_INTERFACE_DBUS,
2011 if( !req ) {
2012 log_err("could not create method call message");
2013 goto EXIT;
2014 }
2015
2016 if( !dbus_message_append_args(req,
2017 DBUS_TYPE_STRING, &name,
2018 DBUS_TYPE_INVALID) ) {
2019 log_err("could not add method call parameters");
2020 goto EXIT;
2021 }
2022
2023 /* Synchronous D-Bus call */
2024 rsp = dbus_connection_send_with_reply_and_block(umdbus_connection, req, -1, &err);
2025
2026 if( !rsp && dbus_error_is_set(&err) ) {
2027 log_err("could not get sender pid for %s: %s: %s", name, err.name, err.message);
2028 goto EXIT;
2029 }
2030
2031 if( !dbus_message_get_args(rsp, &err,
2032 DBUS_TYPE_UINT32, &pid,
2033 DBUS_TYPE_INVALID) ) {
2034 log_err("parse error: %s: %s", err.name, err.message);
2035 goto EXIT;
2036 }
2037
2038 snprintf(path, sizeof path, "/proc/%d", (int)pid);
2039 memset(&st, 0, sizeof st);
2040 if( stat(path, &st) != -1 ) {
2041 uid = st.st_uid;
2042 }
2043
2044EXIT:
2045
2046 if( req ) dbus_message_unref(req);
2047 if( rsp ) dbus_message_unref(rsp);
2048
2049 dbus_error_free(&err);
2050
2051 return uid;
2052}
2053
2054const char *
2055umdbus_arg_type_repr(int type)
2056{
2057 const char *repr = "UNKNOWN";
2058 switch( type ) {
2059 case DBUS_TYPE_INVALID: repr = "INVALID"; break;
2060 case DBUS_TYPE_BYTE: repr = "BYTE"; break;
2061 case DBUS_TYPE_BOOLEAN: repr = "BOOLEAN"; break;
2062 case DBUS_TYPE_INT16: repr = "INT16"; break;
2063 case DBUS_TYPE_UINT16: repr = "UINT16"; break;
2064 case DBUS_TYPE_INT32: repr = "INT32"; break;
2065 case DBUS_TYPE_UINT32: repr = "UINT32"; break;
2066 case DBUS_TYPE_INT64: repr = "INT64"; break;
2067 case DBUS_TYPE_UINT64: repr = "UINT64"; break;
2068 case DBUS_TYPE_DOUBLE: repr = "DOUBLE"; break;
2069 case DBUS_TYPE_STRING: repr = "STRING"; break;
2070 case DBUS_TYPE_OBJECT_PATH: repr = "OBJECT_PATH"; break;
2071 case DBUS_TYPE_SIGNATURE: repr = "SIGNATURE"; break;
2072 case DBUS_TYPE_UNIX_FD: repr = "UNIX_FD"; break;
2073 case DBUS_TYPE_ARRAY: repr = "ARRAY"; break;
2074 case DBUS_TYPE_VARIANT: repr = "VARIANT"; break;
2075 case DBUS_TYPE_STRUCT: repr = "STRUCT"; break;
2076 case DBUS_TYPE_DICT_ENTRY: repr = "DICT_ENTRY"; break;
2077 default: break;
2078 }
2079 return repr;
2080}
2081
2082const char *
2083umdbus_arg_type_signature(int type)
2084{
2085 const char *sign = 0;
2086 switch( type ) {
2087 case DBUS_TYPE_INVALID: sign = DBUS_TYPE_INVALID_AS_STRING; break;
2088 case DBUS_TYPE_BYTE: sign = DBUS_TYPE_BYTE_AS_STRING; break;
2089 case DBUS_TYPE_BOOLEAN: sign = DBUS_TYPE_BOOLEAN_AS_STRING; break;
2090 case DBUS_TYPE_INT16: sign = DBUS_TYPE_INT16_AS_STRING; break;
2091 case DBUS_TYPE_UINT16: sign = DBUS_TYPE_UINT16_AS_STRING; break;
2092 case DBUS_TYPE_INT32: sign = DBUS_TYPE_INT32_AS_STRING; break;
2093 case DBUS_TYPE_UINT32: sign = DBUS_TYPE_UINT32_AS_STRING; break;
2094 case DBUS_TYPE_INT64: sign = DBUS_TYPE_INT64_AS_STRING; break;
2095 case DBUS_TYPE_UINT64: sign = DBUS_TYPE_UINT64_AS_STRING; break;
2096 case DBUS_TYPE_DOUBLE: sign = DBUS_TYPE_DOUBLE_AS_STRING; break;
2097 case DBUS_TYPE_STRING: sign = DBUS_TYPE_STRING_AS_STRING; break;
2098 case DBUS_TYPE_OBJECT_PATH: sign = DBUS_TYPE_OBJECT_PATH_AS_STRING; break;
2099 case DBUS_TYPE_SIGNATURE: sign = DBUS_TYPE_SIGNATURE_AS_STRING; break;
2100 case DBUS_TYPE_UNIX_FD: sign = DBUS_TYPE_UNIX_FD_AS_STRING; break;
2101 case DBUS_TYPE_ARRAY: sign = DBUS_TYPE_ARRAY_AS_STRING; break;
2102 case DBUS_TYPE_VARIANT: sign = DBUS_TYPE_VARIANT_AS_STRING; break;
2103 case DBUS_TYPE_STRUCT: sign = DBUS_TYPE_STRUCT_AS_STRING; break;
2104 case DBUS_TYPE_DICT_ENTRY: sign = DBUS_TYPE_DICT_ENTRY_AS_STRING; break;
2105 default: break;
2106 }
2107 return sign;
2108}
2109
2110const char *
2111umdbus_msg_type_repr(int type)
2112{
2113 return dbus_message_type_to_string(type);
2114}
2115
2116bool
2117umdbus_parser_init(DBusMessageIter *iter, DBusMessage *msg)
2118{
2119 return iter && msg && dbus_message_iter_init(msg, iter);
2120}
2121
2122int
2123umdbus_parser_at_type(DBusMessageIter *iter)
2124{
2125 return iter ? dbus_message_iter_get_arg_type(iter) : DBUS_TYPE_INVALID;
2126}
2127
2128bool
2129umdbus_parser_at_end(DBusMessageIter *iter)
2130{
2131 return umdbus_parser_at_type(iter) == DBUS_TYPE_INVALID;
2132}
2133
2134bool
2135umdbus_parser_require_type(DBusMessageIter *iter, int type, bool strict)
2136{
2137 int have = umdbus_parser_at_type(iter);
2138
2139 if( have == type )
2140 return true;
2141
2142 if( strict || have != DBUS_TYPE_INVALID )
2143 log_warning("expected %s, got %s",
2144 umdbus_arg_type_repr(type),
2145 umdbus_arg_type_repr(have));
2146 return false;
2147}
2148
2149bool
2150umdbus_parser_get_bool(DBusMessageIter *iter, bool *pval)
2151{
2152 dbus_bool_t val = 0;
2153 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_BOOLEAN, true);
2154 if( ack ) {
2155 dbus_message_iter_get_basic(iter, &val);
2156 dbus_message_iter_next(iter);
2157 }
2158 return *pval = val, ack;
2159}
2160
2161bool
2162umdbus_parser_get_int(DBusMessageIter *iter, int *pval)
2163{
2164 dbus_int32_t val = 0;
2165 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_INT32, true);
2166 if( ack ) {
2167 dbus_message_iter_get_basic(iter, &val);
2168 dbus_message_iter_next(iter);
2169 }
2170 return *pval = (int)val, ack;
2171}
2172
2173bool
2174umdbus_parser_get_string(DBusMessageIter *iter, const char **pval)
2175{
2176 const char *val = 0;
2177 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_STRING, true);
2178 if( ack ) {
2179 dbus_message_iter_get_basic(iter, &val);
2180 dbus_message_iter_next(iter);
2181 }
2182 return *pval = val, ack;
2183}
2184
2185bool
2186umdbus_parser_get_object(DBusMessageIter *iter, const char **pval)
2187{
2188 const char *val = 0;
2189 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_OBJECT_PATH, true);
2190 if( ack ) {
2191 dbus_message_iter_get_basic(iter, &val);
2192 dbus_message_iter_next(iter);
2193 }
2194 return *pval = val, ack;
2195}
2196
2197bool
2198umdbus_parser_get_variant(DBusMessageIter *iter, DBusMessageIter *val)
2199{
2200 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_VARIANT, true);
2201 if( ack ) {
2202 dbus_message_iter_recurse(iter, val);
2203 dbus_message_iter_next(iter);
2204 }
2205 return ack;
2206}
2207
2208bool
2209umdbus_parser_get_array(DBusMessageIter *iter, DBusMessageIter *val)
2210{
2211 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_ARRAY, true);
2212 if( ack ) {
2213 dbus_message_iter_recurse(iter, val);
2214 dbus_message_iter_next(iter);
2215 }
2216 return ack;
2217}
2218
2219bool
2220umdbus_parser_get_struct(DBusMessageIter *iter, DBusMessageIter *val)
2221{
2222 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_STRUCT, false);
2223 if( ack ) {
2224 dbus_message_iter_recurse(iter, val);
2225 dbus_message_iter_next(iter);
2226 }
2227 return ack;
2228}
2229
2230bool
2231umdbus_parser_get_entry(DBusMessageIter *iter, DBusMessageIter *val)
2232{
2233 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_DICT_ENTRY, false);
2234 if( ack ) {
2235 dbus_message_iter_recurse(iter, val);
2236 dbus_message_iter_next(iter);
2237 }
2238 return ack;
2239}
2240
2241bool
2242umdbus_append_init(DBusMessageIter *iter, DBusMessage *msg)
2243{
2244 bool ack = iter && msg && (dbus_message_iter_init_append(msg, iter), true);
2245 return ack;
2246}
2247
2248bool
2249umdbus_open_container(DBusMessageIter *iter, DBusMessageIter *sub, int type, const char *sign)
2250{
2251 bool ack = dbus_message_iter_open_container(iter, type, sign, sub);
2252 if( ack ) {
2253 /* Caller must make call umdbus_close_container() */
2254 }
2255 else {
2256 /* Caller must not call umdbus_close_container() */
2257 log_warning("failed to open %s container with signature: %s",
2258 umdbus_arg_type_repr(type), sign ?: "");
2259 }
2260 return ack;
2261}
2262
2263bool
2264umdbus_close_container(DBusMessageIter *iter, DBusMessageIter *sub, bool success)
2265{
2266 if( success ) {
2267 if( !(success = dbus_message_iter_close_container(iter, sub)) ) {
2268 log_warning("failed to close container");
2269 }
2270 }
2271 else {
2272 log_warning("abandoning container");
2273 dbus_message_iter_abandon_container(iter, sub);
2274 }
2275 return success;
2276}
2277
2278bool
2279umdbus_append_basic_value(DBusMessageIter *iter, int type, const DBusBasicValue *val)
2280{
2281 if( log_p(LOG_DEBUG) ) {
2282 char buff[64] = "";
2283 const char *repr = buff;
2284 switch( type ) {
2285 case DBUS_TYPE_BYTE:
2286 snprintf(buff, sizeof buff, "%u", val->byt);
2287 break;
2288 case DBUS_TYPE_BOOLEAN:
2289 repr = val->bool_val ? "true" : "false";
2290 break;
2291 case DBUS_TYPE_INT16:
2292 snprintf(buff, sizeof buff, "%d", val->i16);
2293 break;
2294 case DBUS_TYPE_UINT16:
2295 snprintf(buff, sizeof buff, "%u", val->u16);
2296 break;
2297 case DBUS_TYPE_INT32:
2298 snprintf(buff, sizeof buff, "%d", val->i32);
2299 break;
2300 case DBUS_TYPE_UINT32:
2301 snprintf(buff, sizeof buff, "%u", val->u32);
2302 break;
2303 case DBUS_TYPE_INT64:
2304 snprintf(buff, sizeof buff, "%lld", (long long)val->i64);
2305 break;
2306 case DBUS_TYPE_UINT64:
2307 snprintf(buff, sizeof buff, "%llu", (unsigned long long)val->u64);
2308 break;
2309 case DBUS_TYPE_DOUBLE:
2310 snprintf(buff, sizeof buff, "%g", val->dbl);
2311 break;
2312 case DBUS_TYPE_STRING:
2313 case DBUS_TYPE_OBJECT_PATH:
2314 case DBUS_TYPE_SIGNATURE:
2315 repr = (const char *)val->str;
2316 break;
2317 case DBUS_TYPE_UNIX_FD:
2318 snprintf(buff, sizeof buff, "%d", val->fd);
2319 break;
2320 default:
2321 case DBUS_TYPE_INVALID:
2322 case DBUS_TYPE_ARRAY:
2323 case DBUS_TYPE_VARIANT:
2324 case DBUS_TYPE_STRUCT:
2325 case DBUS_TYPE_DICT_ENTRY:
2326 // not expected
2327 break;
2328 }
2329 log_debug("append %s value %s", umdbus_arg_type_repr(type), repr);
2330 }
2331
2332 if (dbus_message_iter_append_basic(iter, type, val))
2333 return true;
2334
2335 log_warning("failed to append %s argument", umdbus_arg_type_repr(type));
2336 return false;
2337}
2338
2339bool
2340umdbus_append_basic_variant(DBusMessageIter *iter, int type, const DBusBasicValue *val)
2341{
2342 bool ack = false;
2343 const char *sign = 0;
2344
2345 log_debug("append %s variant", umdbus_arg_type_repr(type));
2346
2347 if( !dbus_type_is_basic(type) )
2348 goto EXIT;
2349
2350 if( !(sign = umdbus_arg_type_signature(type)) )
2351 goto EXIT;
2352
2353 DBusMessageIter var;
2354
2355 if( umdbus_open_container(iter, &var, DBUS_TYPE_VARIANT, sign) ) {
2356 ack = umdbus_append_basic_value(&var, DBUS_TYPE_BOOLEAN, val);
2357 ack = umdbus_close_container(iter, &var, ack);
2358 }
2359
2360EXIT:
2361
2362 if( !ack )
2363 log_warning("failed to append %s variant", umdbus_arg_type_repr(type));
2364
2365 return ack;
2366}
2367
2368bool
2369umdbus_append_bool(DBusMessageIter *iter, bool val)
2370{
2371 DBusBasicValue dta = { .bool_val = (dbus_bool_t)val };
2372 return umdbus_append_basic_value(iter, DBUS_TYPE_BOOLEAN, &dta);
2373}
2374
2375bool
2376umdbus_append_int(DBusMessageIter *iter, int val)
2377{
2378 DBusBasicValue dta = { .i32 = (dbus_int32_t)val };
2379 return umdbus_append_basic_value(iter, DBUS_TYPE_INT32, &dta);
2380}
2381
2382bool
2383umdbus_append_string(DBusMessageIter *iter, const char *val)
2384{
2385 DBusBasicValue dta = { .str = (char *)val };
2386 return umdbus_append_basic_value(iter, DBUS_TYPE_STRING, &dta);
2387}
2388
2389bool
2390umdbus_append_bool_variant(DBusMessageIter *iter, bool val)
2391{
2392 DBusBasicValue dta = { .bool_val = val };
2393 return umdbus_append_basic_variant(iter, DBUS_TYPE_BOOLEAN, &dta);
2394}
2395
2396bool
2397umdbus_append_int_variant(DBusMessageIter *iter, int val)
2398{
2399 DBusBasicValue dta = { .i32 = val };
2400 return umdbus_append_basic_variant(iter, DBUS_TYPE_INT32, &dta);
2401}
2402
2403bool
2404umdbus_append_string_variant(DBusMessageIter *iter, const char *val)
2405{
2406 DBusBasicValue dta = { .str = (char *)val };
2407 return umdbus_append_basic_variant(iter, DBUS_TYPE_STRING, &dta);
2408}
2409
2410bool
2411umdbus_append_args_va(DBusMessageIter *iter, int type, va_list va)
2412{
2413 bool ack = false;
2414
2415 DBusBasicValue *arg;
2416
2417 while( type != DBUS_TYPE_INVALID ) {
2418 switch( type ) {
2419 case DBUS_TYPE_VARIANT:
2420 type = va_arg(va, int);
2421 if( !dbus_type_is_basic(type) ) {
2422 log_err("variant type %s is not supported",
2423 umdbus_arg_type_repr(type));
2424 goto EXIT;
2425 }
2426 arg = va_arg(va, DBusBasicValue *);
2427 if( !umdbus_append_basic_variant(iter, type, arg) )
2428 goto EXIT;
2429
2430 break;
2431
2432 case DBUS_TYPE_ARRAY:
2433 case DBUS_TYPE_STRUCT:
2434 /* Not supported yet - fall through */
2435 default:
2436 if( !dbus_type_is_basic(type) ) {
2437 log_err("value type %s is not supported",
2438 umdbus_arg_type_repr(type));
2439 goto EXIT;
2440 }
2441 arg = va_arg(va, DBusBasicValue *);
2442 if( !umdbus_append_basic_value(iter, type, arg) )
2443 goto EXIT;
2444 break;
2445 }
2446 type = va_arg(va, int);
2447 }
2448 ack = true;
2449EXIT:
2450 return ack;
2451}
2452
2453bool
2454umdbus_append_args(DBusMessageIter *iter, int arg_type, ...)
2455{
2456 va_list va;
2457 va_start(va, arg_type);
2458 bool ack = umdbus_append_args_va(iter, arg_type, va);
2459 va_end(va);
2460 return ack;
2461}
2462
2463DBusMessage *
2464umdbus_blocking_call(DBusConnection *con,
2465 const char *dst,
2466 const char *obj,
2467 const char *iface,
2468 const char *meth,
2469 DBusError *err,
2470 int arg_type, ...)
2471{
2472 DBusMessage *rsp = 0;
2473 DBusMessage *req = 0;
2474 va_list va;
2475
2476 va_start(va, arg_type);
2477
2478 if( !(req = dbus_message_new_method_call(dst, obj, iface, meth)) )
2479 goto EXIT;
2480
2481 DBusMessageIter body;
2482 if( !umdbus_append_init(&body, req) )
2483 goto EXIT;
2484
2485 /* Note: Unlike dbus_message_append_args_valist():
2486 * - simple variants are supported
2487 * - arrays are not (yet)
2488 */
2489 if( !umdbus_append_args_va(&body, arg_type, va) )
2490 goto EXIT;
2491
2492 if( !(rsp = dbus_connection_send_with_reply_and_block(con, req, -1, err)) ) {
2493 log_warning("no reply to %s.%s(): %s: %s",
2494 iface, meth, err->name, err->message);
2495 goto EXIT;
2496 }
2497
2498 if( dbus_set_error_from_message(err, rsp) ) {
2499 log_warning("error reply to %s.%s(): %s: %s",
2500 iface, meth, err->name, err->message);
2501 dbus_message_unref(rsp), rsp = 0;
2502 goto EXIT;
2503 }
2504
2505 log_debug("blocking %s.%s() call succeeded", iface, meth);
2506
2507EXIT:
2508 if( req )
2509 dbus_message_unref(req);
2510
2511 va_end(va);
2512
2513 return rsp;
2514}
2515
2516bool
2517umdbus_parse_reply(DBusMessage *rsp, int arg_type, ...)
2518{
2519 bool ack = false;
2520 DBusError err = DBUS_ERROR_INIT;
2521 va_list va;
2522
2523 va_start(va, arg_type);
2524
2525 if( !rsp )
2526 goto EXIT;
2527
2528 /* Note: It is assumed that differentiation between replies and
2529 * error replies is done elsewhere.
2530 */
2531
2532 if( !dbus_message_get_args_valist(rsp, &err, arg_type, va) ) {
2533 log_warning("parse error: %s: %s", err.name, err.message);
2534 goto EXIT;
2535 }
2536
2537 ack = true;
2538
2539EXIT:
2540 dbus_error_free(&err);
2541
2542 va_end(va);
2543
2544 return ack;
2545}
const member_info_t * members
const char * interface
const char * args
const char * member
void(* handler)(umdbus_context_t *)
const char * object
const interface_info_t ** interfaces
const interface_info_t * interface_info
DBusMessage * msg
DBusMessage * rsp
const object_info_t * object_info
const char * object
const char * interface
const char * sender
const char * member
const member_info_t * member_info
int common_valid_mode(const char *mode)
gchar * common_get_mode_list(mode_list_type_t type, uid_t uid)
@ AVAILABLE_MODES_LIST
@ SUPPORTED_MODES_LIST
bool config_user_clear(uid_t uid)
bool control_select_mode(const char *mode)
cable_state_t control_get_cable_state(void)
#define DBUS_GET_CONNECTION_PID_REQ
#define DBUS_GET_NAME_OWNER_REQ
void umdbus_dump_introspect_xml(void)
int umdbus_send_hidden_modes_signal(const char *hidden_modes)
void umdbus_send_current_state_signal(const char *state_ind)
void umdbus_cleanup(void)
void umdbus_send_target_state_signal(const char *state_ind)
void umdbus_send_event_signal(const char *state_ind)
#define ADD_SENTINEL
gboolean umdbus_init_service(void)
void umdbus_dump_busconfig_xml(void)
int umdbus_send_error_signal(const char *error)
gboolean umdbus_get_name_owner_async(const char *name, usb_moded_get_name_owner_fn cb, DBusPendingCall **ppc)
int umdbus_send_available_modes_signal(const char *available_modes)
void umdbus_send_config_signal(const char *section, const char *key, const char *value)
gboolean umdbus_init_connection(void)
int umdbus_send_supported_modes_signal(const char *supported_modes)
#define ADD_SIGNAL(NAME, ARGS)
#define ADD_METHOD(NAME, FUNC, ARGS)
int umdbus_send_whitelisted_modes_signal(const char *whitelist)
#define USB_MODE_SIGNAL_NAME
bool log_p(int lev)
#define MODE_CHARGING
#define MODE_CHARGING_FALLBACK
#define MODE_BUSY
void network_update(void)
void usbmoded_set_init_done(bool reached)
Definition usb_moded.c:633
const modedata_t * usbmoded_get_modedata(const char *modename)
Definition usb_moded.c:252
void usbmoded_probe_init_done(void)
Definition usb_moded.c:651