usb_moded 0.86.0+mer64
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 DBusError err = DBUS_ERROR_INIT;
921
922 if( !dbus_message_get_args(context->msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID) ) {
923 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, context->member);
924 }
925 else {
926 gchar *setting = config_get_network_setting(config);
927 if( !setting )
928 setting = config_get_network_fallback(config);
929 if( setting ) {
930 if( (context->rsp = dbus_message_new_method_return(context->msg)) )
931 dbus_message_append_args(context->rsp, DBUS_TYPE_STRING, &config, DBUS_TYPE_STRING, &setting, DBUS_TYPE_INVALID);
932 }
933 else {
934 context->rsp = dbus_message_new_error(context->msg, DBUS_ERROR_INVALID_ARGS, config);
935 }
936 g_free(setting);
937 }
938 dbus_error_free(&err);
939}
940
941/* ------------------------------------------------------------------------- *
942 * miscellaneous
943 * ------------------------------------------------------------------------- */
944
947static void
948usb_moded_rescue_off_cb(umdbus_context_t *context)
949{
950 LOG_REGISTER_CONTEXT;
951
952 usbmoded_set_rescue_mode(false);
953 log_debug("Rescue mode off\n ");
954 context->rsp = dbus_message_new_method_return(context->msg);
955}
956
957static const member_info_t usb_moded_members[] =
958{
959 ADD_METHOD(USB_MODE_STATE_REQUEST,
960 usb_moded_state_request_cb,
961 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
962 ADD_METHOD(USB_MODE_TARGET_STATE_GET,
963 usb_moded_target_state_get_cb,
964 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
965 ADD_METHOD(USB_MODE_TARGET_CONFIG_GET,
966 usb_moded_target_config_get_cb,
967 " <arg name=\"config\" type=\"a{sv}\" direction=\"out\"/>\n"
968 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QVariantMap\"/>\n"),
969 ADD_METHOD(USB_MODE_STATE_SET,
970 usb_moded_state_set_cb,
971 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
972 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
973 ADD_METHOD(USB_MODE_CONFIG_SET,
974 usb_moded_config_set_cb,
975 " <arg name=\"config\" type=\"s\" direction=\"in\"/>\n"
976 " <arg name=\"config\" type=\"s\" direction=\"out\"/>\n"),
977 ADD_METHOD(USB_MODE_CONFIG_GET,
978 usb_moded_config_get_cb,
979 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
980 ADD_METHOD(USB_MODE_LIST,
981 usb_moded_mode_list_cb,
982 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
983 ADD_METHOD(USB_MODE_AVAILABLE_MODES_GET,
984 usb_moded_available_modes_get_cb,
985 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
986 ADD_METHOD(USB_MODE_AVAILABLE_MODES_FOR_USER,
987 usb_moded_available_modes_for_user_cb,
988 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
989 ADD_METHOD(USB_MODE_HIDE,
990 usb_moded_mode_hide_cb,
991 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
992 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
993 ADD_METHOD(USB_MODE_UNHIDE,
994 usb_moded_mode_unhide_cb,
995 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
996 " <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"),
997 ADD_METHOD(USB_MODE_HIDDEN_GET,
998 usb_moded_hidden_get_cb,
999 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
1000 ADD_METHOD(USB_MODE_WHITELISTED_MODES_GET,
1001 usb_moded_whitelisted_modes_get_cb,
1002 " <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"),
1003 ADD_METHOD(USB_MODE_WHITELISTED_MODES_SET,
1004 usb_moded_whitelisted_modes_set_cb,
1005 " <arg name=\"modes\" type=\"s\" direction=\"in\"/>\n"),
1006 ADD_METHOD(USB_MODE_WHITELISTED_SET,
1007 usb_moded_whitelisted_set_cb,
1008 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
1009 " <arg name=\"whitelisted\" type=\"b\" direction=\"in\"/>\n"),
1010 ADD_METHOD(USB_MODE_NETWORK_SET,
1011 usb_moded_network_set_cb,
1012 " <arg name=\"key\" type=\"s\" direction=\"in\"/>\n"
1013 " <arg name=\"value\" type=\"s\" direction=\"in\"/>\n"
1014 " <arg name=\"key\" type=\"s\" direction=\"out\"/>\n"
1015 " <arg name=\"value\" type=\"s\" direction=\"out\"/>\n"),
1016 ADD_METHOD(USB_MODE_NETWORK_GET,
1017 usb_moded_network_get_cb,
1018 " <arg name=\"key\" type=\"s\" direction=\"in\"/>\n"
1019 " <arg name=\"key\" type=\"s\" direction=\"out\"/>\n"
1020 " <arg name=\"value\" type=\"s\" direction=\"out\"/>\n"),
1021 ADD_METHOD(USB_MODE_RESCUE_OFF,
1022 usb_moded_rescue_off_cb,
1023 0),
1024 ADD_METHOD(USB_MODE_USER_CONFIG_CLEAR,
1025 usb_moded_user_config_clear_cb,
1026 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"),
1028 " <arg name=\"mode_or_event\" type=\"s\"/>\n"),
1029 ADD_SIGNAL(USB_MODE_CURRENT_STATE_SIGNAL_NAME,
1030 " <arg name=\"mode\" type=\"s\"/>\n"),
1031 ADD_SIGNAL(USB_MODE_TARGET_STATE_SIGNAL_NAME,
1032 " <arg name=\"mode\" type=\"s\"/>\n"),
1033 ADD_SIGNAL(USB_MODE_TARGET_CONFIG_SIGNAL_NAME,
1034 " <arg name=\"config\" type=\"a{sv}\" direction=\"out\"/>\n"
1035 " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QVariantMap\"/>\n"),
1036 ADD_SIGNAL(USB_MODE_EVENT_SIGNAL_NAME,
1037 " <arg name=\"event\" type=\"s\"/>\n"),
1038 ADD_SIGNAL(USB_MODE_CONFIG_SIGNAL_NAME,
1039 " <arg name=\"section\" type=\"s\"/>\n"
1040 " <arg name=\"key\" type=\"s\"/>\n"
1041 " <arg name=\"value\" type=\"s\"/>\n"),
1042 ADD_SIGNAL(USB_MODE_SUPPORTED_MODES_SIGNAL_NAME,
1043 " <arg name=\"modes\" type=\"s\"/>\n"),
1044 ADD_SIGNAL(USB_MODE_AVAILABLE_MODES_SIGNAL_NAME,
1045 " <arg name=\"modes\" type=\"s\"/>\n"),
1046 ADD_SIGNAL(USB_MODE_HIDDEN_MODES_SIGNAL_NAME,
1047 " <arg name=\"modes\" type=\"s\"/>\n"),
1048 ADD_SIGNAL(USB_MODE_WHITELISTED_MODES_SIGNAL_NAME,
1049 " <arg name=\"modes\" type=\"s\"/>\n"),
1050 ADD_SIGNAL(USB_MODE_ERROR_SIGNAL_NAME,
1051 " <arg name=\"error\" type=\"s\"/>\n"),
1053};
1054
1055static const interface_info_t usb_moded_interface = {
1056 .interface = USB_MODE_INTERFACE,
1057 .members = usb_moded_members
1058};
1059
1060/* ========================================================================= *
1061 * Functions
1062 * ========================================================================= */
1063
1066static const interface_info_t *standard_interfaces[] = {
1067 &introspectable_interface,
1068 &peer_interface,
1069 0
1070};
1071
1074static const interface_info_t *usb_moded_interfaces[] = {
1075 &introspectable_interface,
1076 &peer_interface,
1077 &usb_moded_interface,
1078 0
1079};
1080
1083static const object_info_t usb_moded_objects[] =
1084{
1085 /* NOTE: Parents must be listed before children.
1086 * See object_info_introspect().
1087 */
1088 {
1089 .object = "/",
1090 .interfaces = standard_interfaces,
1091 },
1092 {
1093 .object = "/com",
1094 .interfaces = standard_interfaces,
1095 },
1096 {
1097 .object = "/com/meego",
1098 .interfaces = standard_interfaces,
1099 },
1100 {
1101 .object = USB_MODE_OBJECT, // = "/com/meego/usb_moded"
1102 .interfaces = usb_moded_interfaces,
1103 },
1104 {
1105 .object = 0
1106 },
1107};
1108
1111static const object_info_t *
1112umdbus_get_object_info(const char *object)
1113{
1114 LOG_REGISTER_CONTEXT;
1115
1116 const object_info_t *obj = 0;
1117
1118 if( !object )
1119 goto EXIT;
1120
1121 for( size_t i = 0; usb_moded_objects[i].object; ++i ) {
1122 if( !strcmp(usb_moded_objects[i].object, object) ) {
1123 obj = &usb_moded_objects[i];
1124 break;
1125 }
1126 }
1127
1128EXIT:
1129 return obj;
1130}
1131
1136void
1138{
1139 LOG_REGISTER_CONTEXT;
1140
1141 const object_info_t *object_info = umdbus_get_object_info(USB_MODE_OBJECT);
1142 char *xml = object_info_get_introspect_xml(object_info, USB_MODE_INTERFACE);
1143 fprintf(stdout, "%s", xml ?: "\n");
1144 free(xml);
1145};
1146
1151void
1153{
1154 LOG_REGISTER_CONTEXT;
1155
1156 static const char dtd[] =
1157 "<!DOCTYPE busconfig PUBLIC\n"
1158 " \"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN\"\n"
1159 " \"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\">\n";
1160
1161 fprintf(stdout, "%s\n", dtd);
1162 fprintf(stdout, "<busconfig>\n");
1163
1164 fprintf(stdout,
1165 " <policy user=\"root\">\n"
1166 " <allow own=\"" USB_MODE_SERVICE "\"/>\n"
1167 " <allow send_destination=\"" USB_MODE_SERVICE "\"\n"
1168 " send_interface=\"" USB_MODE_INTERFACE "\"/>\n"
1169 " </policy>\n");
1170
1171 fprintf(stdout,
1172 " <policy context=\"default\">\n"
1173 " <deny own=\"" USB_MODE_SERVICE "\"/>\n"
1174 " <deny send_destination=\"" USB_MODE_SERVICE "\"\n"
1175 " send_interface=\"" USB_MODE_INTERFACE "\"/>\n"
1176 " <allow send_destination=\"" USB_MODE_SERVICE "\"\n"
1177 " send_interface=\"org.freedesktop.DBus.Introspectable\"/>\n");
1178
1179 for( const member_info_t *mem = usb_moded_members; mem->member; ++mem ) {
1180 if( mem->type != DBUS_MESSAGE_TYPE_METHOD_CALL )
1181 continue;
1182 fprintf(stdout,
1183 " <allow send_destination=\"" USB_MODE_SERVICE "\"\n"
1184 " send_interface=\"" USB_MODE_INTERFACE "\"\n"
1185 " send_member=\"%s\"/>\n",
1186 mem->member);
1187 }
1188 fprintf(stdout, " </policy>\n");
1189 fprintf(stdout, "</busconfig>\n");
1190}
1191
1195void umdbus_send_config_signal(const char *section, const char *key, const char *value)
1196{
1197 LOG_REGISTER_CONTEXT;
1198
1199 DBusMessage* msg = 0;
1200
1201 if( !section || !key || !value ) {
1202 log_err("config notification with NULL %s",
1203 !section ? "section" : !key ? "key" : value);
1204 goto EXIT;
1205 }
1206
1207 if( !umdbus_service_name_acquired ) {
1208 log_err("config notification without service: [%s] %s=%s",
1209 section, key, value);
1210 goto EXIT;
1211 }
1212
1213 if( !umdbus_connection ) {
1214 log_err("config notification without connection: [%s] %s=%s",
1215 section, key, value);
1216 goto EXIT;
1217 }
1218
1219 log_debug("broadcast signal %s(%s, %s, %s)\n", USB_MODE_CONFIG_SIGNAL_NAME, section, key, value);
1220
1221 msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE, USB_MODE_CONFIG_SIGNAL_NAME);
1222 if( !msg )
1223 goto EXIT;
1224
1225 dbus_message_append_args(msg, DBUS_TYPE_STRING, &section,
1226 DBUS_TYPE_STRING, &key,
1227 DBUS_TYPE_STRING, &value,
1228 DBUS_TYPE_INVALID);
1229 dbus_connection_send(umdbus_connection, msg, NULL);
1230
1231EXIT:
1232 if( msg )
1233 dbus_message_unref(msg);
1234}
1235
1236static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data)
1237{
1238 (void)user_data;
1239
1240 LOG_REGISTER_CONTEXT;
1241
1242 DBusHandlerResult status = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1243
1244 umdbus_context_t context = { .msg = msg, };
1245
1246 /* We are only interested in signals and method calls */
1247 switch( (context.type = dbus_message_get_type(msg)) ) {
1248 case DBUS_MESSAGE_TYPE_SIGNAL:
1249 case DBUS_MESSAGE_TYPE_METHOD_CALL:
1250 break;
1251 default:
1252 goto EXIT;
1253 }
1254
1255 /* Parse message basic info */
1256 if( !(context.sender = dbus_message_get_sender(msg)) )
1257 goto EXIT;
1258
1259 if( !(context.object = dbus_message_get_path(msg)) )
1260 goto EXIT;
1261
1262 if( !(context.interface = dbus_message_get_interface(msg)) )
1263 goto EXIT;
1264
1265 if( !(context.member = dbus_message_get_member(msg)) )
1266 goto EXIT;
1267
1268 log_debug("DBUS %s %s.%s from %s",
1269 dbus_message_type_to_string(context.type),
1270 context.interface, context.member, context.sender);
1271
1272 /* Deal with incoming signals */
1273 if( context.type == DBUS_MESSAGE_TYPE_SIGNAL ) {
1274 if( !strcmp(context.interface, INIT_DONE_INTERFACE) && !strcmp(context.member, INIT_DONE_SIGNAL) ) {
1275 /* Update the cached state value */
1277 }
1278 goto EXIT;
1279 }
1280
1281 /* Locate and use method call handler */
1282 context.object_info = umdbus_get_object_info(context.object);
1283 context.interface_info = object_info_get_interface(context.object_info,
1284 context.interface);
1285 context.member_info = interface_info_get_member(context.interface_info,
1286 context.member);
1287
1288 if( context.member_info && context.member_info->type == context.type ) {
1289 if( context.member_info->handler )
1290 context.member_info->handler(&context);
1291 }
1292 else if( !context.object_info ) {
1293 context.rsp = dbus_message_new_error_printf(context.msg,
1294 DBUS_ERROR_UNKNOWN_OBJECT,
1295 "Object '%s' does not exist",
1296 context.object);
1297 }
1298 else if( !context.interface_info ) {
1299 context.rsp = dbus_message_new_error_printf(context.msg,
1300 DBUS_ERROR_UNKNOWN_INTERFACE,
1301 "Interface '%s' does not exist",
1302 context.interface);
1303 }
1304 else {
1305 context.rsp = dbus_message_new_error_printf(context.msg,
1306 DBUS_ERROR_UNKNOWN_METHOD,
1307 "Method '%s.%s' does not exist",
1308 context.interface,
1309 context.member);
1310 }
1311
1312EXIT:
1313 if( context.rsp ) {
1314 status = DBUS_HANDLER_RESULT_HANDLED;
1315 if( !dbus_message_get_no_reply(context.msg) ) {
1316 if( !dbus_connection_send(connection, context.rsp, 0) )
1317 log_debug("Failed sending reply. Out Of Memory!\n");
1318 }
1319 dbus_message_unref(context.rsp);
1320 }
1321
1322 return status;
1323}
1324
1325DBusConnection *umdbus_get_connection(void)
1326{
1327 LOG_REGISTER_CONTEXT;
1328
1329 DBusConnection *connection = 0;
1330 if( umdbus_connection )
1331 connection = dbus_connection_ref(umdbus_connection);
1332 else
1333 log_err("something asked for connection ref while unconnected");
1334 return connection;
1335}
1336
1343{
1344 LOG_REGISTER_CONTEXT;
1345
1346 gboolean status = FALSE;
1347 DBusError error = DBUS_ERROR_INIT;
1348
1349 /* connect to system bus */
1350 if ((umdbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL)
1351 {
1352 log_debug("Failed to open connection to system message bus; %s\n", error.message);
1353 goto EXIT;
1354 }
1355
1356 /* Initialise message handlers */
1357 if (!dbus_connection_add_filter(umdbus_connection, umdbus_msg_handler, NULL, NULL))
1358 goto EXIT;
1359
1360 /* Listen to init-done signals */
1361 dbus_bus_add_match(umdbus_connection, INIT_DONE_MATCH, 0);
1362
1363 /* Re-check flag file after adding signal listener */
1365
1366 /* Connect D-Bus to the mainloop */
1367 dbus_gmain_set_up_connection(umdbus_connection, NULL);
1368
1369 /* everything went fine */
1370 status = TRUE;
1371
1372EXIT:
1373 dbus_error_free(&error);
1374 return status;
1375}
1376
1383{
1384 LOG_REGISTER_CONTEXT;
1385
1386 gboolean status = FALSE;
1387 DBusError error = DBUS_ERROR_INIT;
1388 int ret;
1389
1390 if( !umdbus_connection ) {
1391 goto EXIT;
1392 }
1393
1394 /* Acquire D-Bus service */
1395 ret = dbus_bus_request_name(umdbus_connection, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
1396 if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
1397 {
1398 log_debug("failed claiming dbus name\n");
1399 if( dbus_error_is_set(&error) )
1400 log_debug("DBUS ERROR: %s, %s", error.name, error.message);
1401 goto EXIT;
1402 }
1403 log_debug("claimed name %s", USB_MODE_SERVICE);
1404 umdbus_service_name_acquired = TRUE;
1405 /* everything went fine */
1406 status = TRUE;
1407
1408EXIT:
1409 dbus_error_free(&error);
1410 return status;
1411}
1412
1415static void umdbus_cleanup_service(void)
1416{
1417 LOG_REGISTER_CONTEXT;
1418
1419 if( !umdbus_service_name_acquired )
1420 goto EXIT;
1421
1422 umdbus_service_name_acquired = FALSE;
1423 log_debug("release name %s", USB_MODE_SERVICE);
1424
1425 if( umdbus_connection &&
1426 dbus_connection_get_is_connected(umdbus_connection) )
1427 {
1428 dbus_bus_release_name(umdbus_connection, USB_MODE_SERVICE, NULL);
1429 }
1430
1431EXIT:
1432 return;
1433}
1434
1440{
1441 LOG_REGISTER_CONTEXT;
1442
1443 /* clean up system bus connection */
1444 if (umdbus_connection != NULL)
1445 {
1446 umdbus_cleanup_service();
1447
1448 dbus_connection_remove_filter(umdbus_connection, umdbus_msg_handler, NULL);
1449
1450 dbus_connection_unref(umdbus_connection),
1451 umdbus_connection = NULL;
1452 }
1453}
1454
1461static DBusMessage*
1462umdbus_new_signal(const char *signal_name)
1463{
1464 LOG_REGISTER_CONTEXT;
1465
1466 DBusMessage *msg = 0;
1467
1468 if( !umdbus_connection )
1469 {
1470 log_err("sending signal %s without dbus connection", signal_name);
1471 goto EXIT;
1472 }
1473 if( !umdbus_service_name_acquired )
1474 {
1475 log_err("sending signal %s before acquiring name", signal_name);
1476 goto EXIT;
1477 }
1478 // create a signal and check for errors
1479 msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE,
1480 signal_name );
1481 if( !msg )
1482 {
1483 log_err("allocating signal %s failed", signal_name);
1484 goto EXIT;
1485 }
1486
1487EXIT:
1488 return msg;
1489}
1490
1499static int
1500umdbus_send_signal_ex(const char *signal_name, const char *content)
1501{
1502 LOG_REGISTER_CONTEXT;
1503
1504 int result = 1;
1505 DBusMessage* msg = 0;
1506
1507 /* Assume NULL content equals no value / empty list, and that skipping
1508 * signal broadcast is never preferable over sending empty string. */
1509 if( !content )
1510 content = "";
1511
1512 log_debug("broadcast signal %s(%s)", signal_name, content);
1513
1514 if( !(msg = umdbus_new_signal(signal_name)) )
1515 goto EXIT;
1516
1517 // append arguments onto signal
1518 if( !dbus_message_append_args(msg,
1519 DBUS_TYPE_STRING, &content,
1520 DBUS_TYPE_INVALID) )
1521 {
1522 log_err("appending arguments to signal %s failed", signal_name);
1523 goto EXIT;
1524 }
1525
1526 // send the message on the correct bus
1527 if( !dbus_connection_send(umdbus_connection, msg, 0) )
1528 {
1529 log_err("sending signal %s failed", signal_name);
1530 goto EXIT;
1531 }
1532 result = 0;
1533
1534EXIT:
1535 // free the message
1536 if(msg != 0)
1537 dbus_message_unref(msg);
1538
1539 return result;
1540}
1541
1549static void umdbus_send_legacy_signal(const char *state_ind)
1550{
1551 LOG_REGISTER_CONTEXT;
1552
1553 umdbus_send_signal_ex(USB_MODE_SIGNAL_NAME, state_ind);
1554}
1555
1560void umdbus_send_current_state_signal(const char *state_ind)
1561{
1562 LOG_REGISTER_CONTEXT;
1563
1564 umdbus_send_signal_ex(USB_MODE_CURRENT_STATE_SIGNAL_NAME,
1565 state_ind);
1566 umdbus_send_legacy_signal(state_ind);
1567}
1568
1578static bool
1579umdbus_append_basic_entry(DBusMessageIter *iter, const char *key,
1580 int type, const void *val)
1581{
1582 LOG_REGISTER_CONTEXT;
1583
1584 /* Signature must be provided for variant containers */
1585 const char *signature = 0;
1586 switch( type ) {
1587 case DBUS_TYPE_INT32: signature = DBUS_TYPE_INT32_AS_STRING; break;
1588 case DBUS_TYPE_STRING: signature = DBUS_TYPE_STRING_AS_STRING; break;
1589 default: break;
1590 }
1591 if( !signature ) {
1592 log_err("unhandled D-Bus type: %d", type);
1593 goto bailout_message;
1594 }
1595
1596 DBusMessageIter entry, variant;
1597
1598 if( !dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
1599 0, &entry) )
1600 goto bailout_message;
1601
1602 if( !dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key) )
1603 goto bailout_entry;
1604
1605 if( !dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1606 signature, &variant) )
1607 goto bailout_entry;
1608
1609 if( !dbus_message_iter_append_basic(&variant, type, val) )
1610 goto bailout_variant;
1611
1612 if( !dbus_message_iter_close_container(&entry, &variant) )
1613 goto bailout_variant;
1614
1615 if( !dbus_message_iter_close_container(iter, &entry) )
1616 goto bailout_entry;
1617
1618 return true;
1619
1620bailout_variant:
1621 dbus_message_iter_abandon_container(&entry, &variant);
1622
1623bailout_entry:
1624 dbus_message_iter_abandon_container(iter, &entry);
1625
1626bailout_message:
1627 return false;
1628}
1629
1638static bool
1639umdbus_append_int32_entry(DBusMessageIter *iter, const char *key, int val)
1640{
1641 LOG_REGISTER_CONTEXT;
1642
1643 dbus_int32_t arg = val;
1644 return umdbus_append_basic_entry(iter, key, DBUS_TYPE_INT32, &arg);
1645}
1646
1655static bool
1656umdbus_append_string_entry(DBusMessageIter *iter, const char *key,
1657 const char *val)
1658{
1659 LOG_REGISTER_CONTEXT;
1660
1661 if( !val )
1662 val = "";
1663 return umdbus_append_basic_entry(iter, key, DBUS_TYPE_STRING, &val);
1664}
1665
1673static bool
1674umdbus_append_mode_details(DBusMessage *msg, const char *mode_name)
1675{
1676 LOG_REGISTER_CONTEXT;
1677
1678 const modedata_t *data = usbmoded_get_modedata(mode_name);
1679
1680 DBusMessageIter body, dict;
1681
1682 dbus_message_iter_init_append(msg, &body);
1683
1684 if( !dbus_message_iter_open_container(&body,
1685 DBUS_TYPE_ARRAY,
1686 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1687 DBUS_TYPE_STRING_AS_STRING
1688 DBUS_TYPE_VARIANT_AS_STRING
1689 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1690 &dict) )
1691 goto bailout_message;
1692
1693 /* Note: mode_name is special case: It needs to be valid even
1694 * if the mode does not have dynamic configuration.
1695 */
1696 if( !umdbus_append_string_entry(&dict, "mode_name", mode_name) )
1697 goto bailout_dict;
1698
1699 /* For the rest of the mode attrs we use fallback data if there
1700 * is no dynamic config / dynamic config does not define some value.
1701 */
1702
1703#define ADD_STR_EX(name, memb) \
1704 if( !umdbus_append_string_entry(&dict, #name, data ? data->memb : 0) )\
1705 goto bailout_dict;
1706#define ADD_STR(name) \
1707 if( !umdbus_append_string_entry(&dict, #name, data ? data->name : 0) )\
1708 goto bailout_dict;
1709#define ADD_INT(name) \
1710 if( !umdbus_append_int32_entry(&dict, #name, data ? data->name : 0) )\
1711 goto bailout_dict;
1712
1713 /* Attributes that we presume to be needed */
1714 ADD_INT(appsync);
1715 ADD_INT(network);
1716 ADD_STR_EX(network_interface, cached_interface);
1717 ADD_INT(nat);
1718 ADD_INT(dhcp_server);
1719#ifdef CONNMAN
1720 ADD_STR(connman_tethering);
1721#endif
1722
1723 /* Attributes that are not exposed for now */
1724#if 0
1725 ADD_INT(mass_storage);
1726 ADD_STR(mode_module);
1727 ADD_STR(sysfs_path);
1728 ADD_STR(sysfs_value);
1729 ADD_STR(sysfs_reset_value);
1730 ADD_STR(android_extra_sysfs_path);
1731 ADD_STR(android_extra_sysfs_value);
1732 ADD_STR(android_extra_sysfs_path2);
1733 ADD_STR(android_extra_sysfs_value2);
1734 ADD_STR(android_extra_sysfs_path3);
1735 ADD_STR(android_extra_sysfs_value3);
1736 ADD_STR(android_extra_sysfs_path4);
1737 ADD_STR(android_extra_sysfs_value4);
1738 ADD_STR(idProduct);
1739 ADD_STR(idVendorOverride);
1740#endif
1741
1742#undef ADD_STR
1743#undef ADD_INT
1744
1745 if( !dbus_message_iter_close_container(&body, &dict) )
1746 goto bailout_dict;
1747
1748 return true;
1749
1750bailout_dict:
1751 dbus_message_iter_abandon_container(&body, &dict);
1752
1753bailout_message:
1754 return false;
1755}
1756
1761static void
1762umdbus_send_mode_details_signal(const char *mode_name)
1763{
1764 DBusMessage* msg = 0;
1765
1766 if( !(msg = umdbus_new_signal(USB_MODE_TARGET_CONFIG_SIGNAL_NAME)) )
1767 goto EXIT;
1768
1769 if( !umdbus_append_mode_details(msg, mode_name) )
1770 goto EXIT;
1771
1772 dbus_connection_send(umdbus_connection, msg, 0);
1773
1774EXIT:
1775 if(msg != 0)
1776 dbus_message_unref(msg);
1777}
1778
1783void umdbus_send_target_state_signal(const char *state_ind)
1784{
1785 LOG_REGISTER_CONTEXT;
1786
1787 /* Send target mode details before claiming intent to
1788 * do mode transition. This way the clients tracking
1789 * configuration changes can assume they have valid
1790 * details immediately when transition begins.
1791 *
1792 * If clients for any reason need to pay closer attention
1793 * to signal timing, the mode_name contained in this broadcast
1794 * can be checked against current / target mode.
1795 */
1796 umdbus_send_mode_details_signal(state_ind);
1797
1798 umdbus_send_signal_ex(USB_MODE_TARGET_STATE_SIGNAL_NAME,
1799 state_ind);
1800}
1801
1806void umdbus_send_event_signal(const char *state_ind)
1807{
1808 LOG_REGISTER_CONTEXT;
1809
1810 umdbus_send_signal_ex(USB_MODE_EVENT_SIGNAL_NAME,
1811 state_ind);
1812 umdbus_send_legacy_signal(state_ind);
1813}
1814
1822int umdbus_send_error_signal(const char *error)
1823{
1824 LOG_REGISTER_CONTEXT;
1825
1826 return umdbus_send_signal_ex(USB_MODE_ERROR_SIGNAL_NAME, error);
1827}
1828
1836int umdbus_send_supported_modes_signal(const char *supported_modes)
1837{
1838 LOG_REGISTER_CONTEXT;
1839
1840 return umdbus_send_signal_ex(USB_MODE_SUPPORTED_MODES_SIGNAL_NAME, supported_modes);
1841}
1842
1850int umdbus_send_available_modes_signal(const char *available_modes)
1851{
1852 LOG_REGISTER_CONTEXT;
1853
1854 return umdbus_send_signal_ex(USB_MODE_AVAILABLE_MODES_SIGNAL_NAME, available_modes);
1855}
1856
1864int umdbus_send_hidden_modes_signal(const char *hidden_modes)
1865{
1866 LOG_REGISTER_CONTEXT;
1867
1868 return umdbus_send_signal_ex(USB_MODE_HIDDEN_MODES_SIGNAL_NAME, hidden_modes);
1869}
1870
1878{
1879 LOG_REGISTER_CONTEXT;
1880
1881 return umdbus_send_signal_ex(USB_MODE_WHITELISTED_MODES_SIGNAL_NAME, whitelist);
1882}
1883
1889static void umdbus_get_name_owner_cb(DBusPendingCall *pc, void *aptr)
1890{
1891 LOG_REGISTER_CONTEXT;
1892
1893 usb_moded_get_name_owner_fn cb = aptr;
1894
1895 DBusMessage *rsp = 0;
1896 const char *dta = 0;
1897 DBusError err = DBUS_ERROR_INIT;
1898
1899 if( !(rsp = dbus_pending_call_steal_reply(pc)) ) {
1900 log_err("did not get reply");
1901 goto EXIT;
1902 }
1903
1904 if( dbus_set_error_from_message(&err, rsp) )
1905 {
1906 if( strcmp(err.name, DBUS_ERROR_NAME_HAS_NO_OWNER) )
1907 log_err("error reply: %s: %s", err.name, err.message);
1908 goto EXIT;
1909 }
1910
1911 if( !dbus_message_get_args(rsp, &err,
1912 DBUS_TYPE_STRING, &dta,
1913 DBUS_TYPE_INVALID) )
1914 {
1915 if( strcmp(err.name, DBUS_ERROR_NAME_HAS_NO_OWNER) )
1916 log_err("parse error: %s: %s", err.name, err.message);
1917 goto EXIT;
1918 }
1919
1920EXIT:
1921 /* Allways call the notification function. Equate any error
1922 * situations with "service does not have an owner". */
1923 cb(dta ?: "");
1924
1925 if( rsp ) dbus_message_unref(rsp);
1926
1927 dbus_error_free(&err);
1928}
1929
1938gboolean umdbus_get_name_owner_async(const char *name,
1939 usb_moded_get_name_owner_fn cb,
1940 DBusPendingCall **ppc)
1941{
1942 LOG_REGISTER_CONTEXT;
1943
1944 gboolean ack = FALSE;
1945 DBusMessage *req = 0;
1946 DBusPendingCall *pc = 0;
1947
1948 if(!umdbus_connection)
1949 goto EXIT;
1950
1951 req = dbus_message_new_method_call(DBUS_INTERFACE_DBUS,
1952 DBUS_PATH_DBUS,
1953 DBUS_INTERFACE_DBUS,
1955 if( !req ) {
1956 log_err("could not create method call message");
1957 goto EXIT;
1958 }
1959
1960 if( !dbus_message_append_args(req,
1961 DBUS_TYPE_STRING, &name,
1962 DBUS_TYPE_INVALID) ) {
1963 log_err("could not add method call parameters");
1964 goto EXIT;
1965 }
1966
1967 if( !dbus_connection_send_with_reply(umdbus_connection, req, &pc, -1) )
1968 goto EXIT;
1969
1970 if( !pc )
1971 goto EXIT;
1972
1973 if( !dbus_pending_call_set_notify(pc, umdbus_get_name_owner_cb, cb, 0) )
1974 goto EXIT;
1975
1976 ack = TRUE;
1977
1978 if( ppc )
1979 *ppc = pc, pc = 0;
1980
1981EXIT:
1982
1983 if( pc ) dbus_pending_call_unref(pc);
1984 if( req ) dbus_message_unref(req);
1985
1986 return ack;
1987}
1988
1995static uid_t
1996umdbus_get_sender_uid(const char *name)
1997{
1998 LOG_REGISTER_CONTEXT;
1999
2000 pid_t pid = PID_UNKNOWN;
2001 uid_t uid = UID_UNKNOWN;
2002 DBusMessage *req = 0;
2003 DBusMessage *rsp = 0;
2004 DBusError err = DBUS_ERROR_INIT;
2005 char path[256];
2006 struct stat st;
2007
2008 if(!umdbus_connection)
2009 goto EXIT;
2010
2011 req = dbus_message_new_method_call(DBUS_INTERFACE_DBUS,
2012 DBUS_PATH_DBUS,
2013 DBUS_INTERFACE_DBUS,
2015 if( !req ) {
2016 log_err("could not create method call message");
2017 goto EXIT;
2018 }
2019
2020 if( !dbus_message_append_args(req,
2021 DBUS_TYPE_STRING, &name,
2022 DBUS_TYPE_INVALID) ) {
2023 log_err("could not add method call parameters");
2024 goto EXIT;
2025 }
2026
2027 /* Synchronous D-Bus call */
2028 rsp = dbus_connection_send_with_reply_and_block(umdbus_connection, req, -1, &err);
2029
2030 if( !rsp && dbus_error_is_set(&err) ) {
2031 log_err("could not get sender pid for %s: %s: %s", name, err.name, err.message);
2032 goto EXIT;
2033 }
2034
2035 if( !dbus_message_get_args(rsp, &err,
2036 DBUS_TYPE_UINT32, &pid,
2037 DBUS_TYPE_INVALID) ) {
2038 log_err("parse error: %s: %s", err.name, err.message);
2039 goto EXIT;
2040 }
2041
2042 snprintf(path, sizeof path, "/proc/%d", (int)pid);
2043 memset(&st, 0, sizeof st);
2044 if( stat(path, &st) != -1 ) {
2045 uid = st.st_uid;
2046 }
2047
2048EXIT:
2049
2050 if( req ) dbus_message_unref(req);
2051 if( rsp ) dbus_message_unref(rsp);
2052
2053 dbus_error_free(&err);
2054
2055 return uid;
2056}
2057
2058const char *
2059umdbus_arg_type_repr(int type)
2060{
2061 const char *repr = "UNKNOWN";
2062 switch( type ) {
2063 case DBUS_TYPE_INVALID: repr = "INVALID"; break;
2064 case DBUS_TYPE_BYTE: repr = "BYTE"; break;
2065 case DBUS_TYPE_BOOLEAN: repr = "BOOLEAN"; break;
2066 case DBUS_TYPE_INT16: repr = "INT16"; break;
2067 case DBUS_TYPE_UINT16: repr = "UINT16"; break;
2068 case DBUS_TYPE_INT32: repr = "INT32"; break;
2069 case DBUS_TYPE_UINT32: repr = "UINT32"; break;
2070 case DBUS_TYPE_INT64: repr = "INT64"; break;
2071 case DBUS_TYPE_UINT64: repr = "UINT64"; break;
2072 case DBUS_TYPE_DOUBLE: repr = "DOUBLE"; break;
2073 case DBUS_TYPE_STRING: repr = "STRING"; break;
2074 case DBUS_TYPE_OBJECT_PATH: repr = "OBJECT_PATH"; break;
2075 case DBUS_TYPE_SIGNATURE: repr = "SIGNATURE"; break;
2076 case DBUS_TYPE_UNIX_FD: repr = "UNIX_FD"; break;
2077 case DBUS_TYPE_ARRAY: repr = "ARRAY"; break;
2078 case DBUS_TYPE_VARIANT: repr = "VARIANT"; break;
2079 case DBUS_TYPE_STRUCT: repr = "STRUCT"; break;
2080 case DBUS_TYPE_DICT_ENTRY: repr = "DICT_ENTRY"; break;
2081 default: break;
2082 }
2083 return repr;
2084}
2085
2086const char *
2087umdbus_arg_type_signature(int type)
2088{
2089 const char *sign = 0;
2090 switch( type ) {
2091 case DBUS_TYPE_INVALID: sign = DBUS_TYPE_INVALID_AS_STRING; break;
2092 case DBUS_TYPE_BYTE: sign = DBUS_TYPE_BYTE_AS_STRING; break;
2093 case DBUS_TYPE_BOOLEAN: sign = DBUS_TYPE_BOOLEAN_AS_STRING; break;
2094 case DBUS_TYPE_INT16: sign = DBUS_TYPE_INT16_AS_STRING; break;
2095 case DBUS_TYPE_UINT16: sign = DBUS_TYPE_UINT16_AS_STRING; break;
2096 case DBUS_TYPE_INT32: sign = DBUS_TYPE_INT32_AS_STRING; break;
2097 case DBUS_TYPE_UINT32: sign = DBUS_TYPE_UINT32_AS_STRING; break;
2098 case DBUS_TYPE_INT64: sign = DBUS_TYPE_INT64_AS_STRING; break;
2099 case DBUS_TYPE_UINT64: sign = DBUS_TYPE_UINT64_AS_STRING; break;
2100 case DBUS_TYPE_DOUBLE: sign = DBUS_TYPE_DOUBLE_AS_STRING; break;
2101 case DBUS_TYPE_STRING: sign = DBUS_TYPE_STRING_AS_STRING; break;
2102 case DBUS_TYPE_OBJECT_PATH: sign = DBUS_TYPE_OBJECT_PATH_AS_STRING; break;
2103 case DBUS_TYPE_SIGNATURE: sign = DBUS_TYPE_SIGNATURE_AS_STRING; break;
2104 case DBUS_TYPE_UNIX_FD: sign = DBUS_TYPE_UNIX_FD_AS_STRING; break;
2105 case DBUS_TYPE_ARRAY: sign = DBUS_TYPE_ARRAY_AS_STRING; break;
2106 case DBUS_TYPE_VARIANT: sign = DBUS_TYPE_VARIANT_AS_STRING; break;
2107 case DBUS_TYPE_STRUCT: sign = DBUS_TYPE_STRUCT_AS_STRING; break;
2108 case DBUS_TYPE_DICT_ENTRY: sign = DBUS_TYPE_DICT_ENTRY_AS_STRING; break;
2109 default: break;
2110 }
2111 return sign;
2112}
2113
2114const char *
2115umdbus_msg_type_repr(int type)
2116{
2117 return dbus_message_type_to_string(type);
2118}
2119
2120bool
2121umdbus_parser_init(DBusMessageIter *iter, DBusMessage *msg)
2122{
2123 return iter && msg && dbus_message_iter_init(msg, iter);
2124}
2125
2126int
2127umdbus_parser_at_type(DBusMessageIter *iter)
2128{
2129 return iter ? dbus_message_iter_get_arg_type(iter) : DBUS_TYPE_INVALID;
2130}
2131
2132bool
2133umdbus_parser_at_end(DBusMessageIter *iter)
2134{
2135 return umdbus_parser_at_type(iter) == DBUS_TYPE_INVALID;
2136}
2137
2138bool
2139umdbus_parser_require_type(DBusMessageIter *iter, int type, bool strict)
2140{
2141 int have = umdbus_parser_at_type(iter);
2142
2143 if( have == type )
2144 return true;
2145
2146 if( strict || have != DBUS_TYPE_INVALID )
2147 log_warning("expected %s, got %s",
2148 umdbus_arg_type_repr(type),
2149 umdbus_arg_type_repr(have));
2150 return false;
2151}
2152
2153bool
2154umdbus_parser_get_bool(DBusMessageIter *iter, bool *pval)
2155{
2156 dbus_bool_t val = 0;
2157 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_BOOLEAN, true);
2158 if( ack ) {
2159 dbus_message_iter_get_basic(iter, &val);
2160 dbus_message_iter_next(iter);
2161 }
2162 return *pval = val, ack;
2163}
2164
2165bool
2166umdbus_parser_get_int(DBusMessageIter *iter, int *pval)
2167{
2168 dbus_int32_t val = 0;
2169 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_INT32, true);
2170 if( ack ) {
2171 dbus_message_iter_get_basic(iter, &val);
2172 dbus_message_iter_next(iter);
2173 }
2174 return *pval = (int)val, ack;
2175}
2176
2177bool
2178umdbus_parser_get_string(DBusMessageIter *iter, const char **pval)
2179{
2180 const char *val = 0;
2181 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_STRING, true);
2182 if( ack ) {
2183 dbus_message_iter_get_basic(iter, &val);
2184 dbus_message_iter_next(iter);
2185 }
2186 return *pval = val, ack;
2187}
2188
2189bool
2190umdbus_parser_get_object(DBusMessageIter *iter, const char **pval)
2191{
2192 const char *val = 0;
2193 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_OBJECT_PATH, true);
2194 if( ack ) {
2195 dbus_message_iter_get_basic(iter, &val);
2196 dbus_message_iter_next(iter);
2197 }
2198 return *pval = val, ack;
2199}
2200
2201bool
2202umdbus_parser_get_variant(DBusMessageIter *iter, DBusMessageIter *val)
2203{
2204 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_VARIANT, true);
2205 if( ack ) {
2206 dbus_message_iter_recurse(iter, val);
2207 dbus_message_iter_next(iter);
2208 }
2209 return ack;
2210}
2211
2212bool
2213umdbus_parser_get_array(DBusMessageIter *iter, DBusMessageIter *val)
2214{
2215 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_ARRAY, true);
2216 if( ack ) {
2217 dbus_message_iter_recurse(iter, val);
2218 dbus_message_iter_next(iter);
2219 }
2220 return ack;
2221}
2222
2223bool
2224umdbus_parser_get_struct(DBusMessageIter *iter, DBusMessageIter *val)
2225{
2226 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_STRUCT, false);
2227 if( ack ) {
2228 dbus_message_iter_recurse(iter, val);
2229 dbus_message_iter_next(iter);
2230 }
2231 return ack;
2232}
2233
2234bool
2235umdbus_parser_get_entry(DBusMessageIter *iter, DBusMessageIter *val)
2236{
2237 bool ack = umdbus_parser_require_type(iter, DBUS_TYPE_DICT_ENTRY, false);
2238 if( ack ) {
2239 dbus_message_iter_recurse(iter, val);
2240 dbus_message_iter_next(iter);
2241 }
2242 return ack;
2243}
2244
2245bool
2246umdbus_append_init(DBusMessageIter *iter, DBusMessage *msg)
2247{
2248 bool ack = iter && msg && (dbus_message_iter_init_append(msg, iter), true);
2249 return ack;
2250}
2251
2252bool
2253umdbus_open_container(DBusMessageIter *iter, DBusMessageIter *sub, int type, const char *sign)
2254{
2255 bool ack = dbus_message_iter_open_container(iter, type, sign, sub);
2256 if( ack ) {
2257 /* Caller must make call umdbus_close_container() */
2258 }
2259 else {
2260 /* Caller must not call umdbus_close_container() */
2261 log_warning("failed to open %s container with signature: %s",
2262 umdbus_arg_type_repr(type), sign ?: "");
2263 }
2264 return ack;
2265}
2266
2267bool
2268umdbus_close_container(DBusMessageIter *iter, DBusMessageIter *sub, bool success)
2269{
2270 if( success ) {
2271 if( !(success = dbus_message_iter_close_container(iter, sub)) ) {
2272 log_warning("failed to close container");
2273 }
2274 }
2275 else {
2276 log_warning("abandoning container");
2277 dbus_message_iter_abandon_container(iter, sub);
2278 }
2279 return success;
2280}
2281
2282bool
2283umdbus_append_basic_value(DBusMessageIter *iter, int type, const DBusBasicValue *val)
2284{
2285 if( log_p(LOG_DEBUG) ) {
2286 char buff[64] = "";
2287 const char *repr = buff;
2288 switch( type ) {
2289 case DBUS_TYPE_BYTE:
2290 snprintf(buff, sizeof buff, "%u", val->byt);
2291 break;
2292 case DBUS_TYPE_BOOLEAN:
2293 repr = val->bool_val ? "true" : "false";
2294 break;
2295 case DBUS_TYPE_INT16:
2296 snprintf(buff, sizeof buff, "%d", val->i16);
2297 break;
2298 case DBUS_TYPE_UINT16:
2299 snprintf(buff, sizeof buff, "%u", val->u16);
2300 break;
2301 case DBUS_TYPE_INT32:
2302 snprintf(buff, sizeof buff, "%d", val->i32);
2303 break;
2304 case DBUS_TYPE_UINT32:
2305 snprintf(buff, sizeof buff, "%u", val->u32);
2306 break;
2307 case DBUS_TYPE_INT64:
2308 snprintf(buff, sizeof buff, "%lld", (long long)val->i64);
2309 break;
2310 case DBUS_TYPE_UINT64:
2311 snprintf(buff, sizeof buff, "%llu", (unsigned long long)val->u64);
2312 break;
2313 case DBUS_TYPE_DOUBLE:
2314 snprintf(buff, sizeof buff, "%g", val->dbl);
2315 break;
2316 case DBUS_TYPE_STRING:
2317 case DBUS_TYPE_OBJECT_PATH:
2318 case DBUS_TYPE_SIGNATURE:
2319 repr = (const char *)val->str;
2320 break;
2321 case DBUS_TYPE_UNIX_FD:
2322 snprintf(buff, sizeof buff, "%d", val->fd);
2323 break;
2324 default:
2325 case DBUS_TYPE_INVALID:
2326 case DBUS_TYPE_ARRAY:
2327 case DBUS_TYPE_VARIANT:
2328 case DBUS_TYPE_STRUCT:
2329 case DBUS_TYPE_DICT_ENTRY:
2330 // not expected
2331 break;
2332 }
2333 log_debug("append %s value %s", umdbus_arg_type_repr(type), repr);
2334 }
2335
2336 if (dbus_message_iter_append_basic(iter, type, val))
2337 return true;
2338
2339 log_warning("failed to append %s argument", umdbus_arg_type_repr(type));
2340 return false;
2341}
2342
2343bool
2344umdbus_append_basic_variant(DBusMessageIter *iter, int type, const DBusBasicValue *val)
2345{
2346 bool ack = false;
2347 const char *sign = 0;
2348
2349 log_debug("append %s variant", umdbus_arg_type_repr(type));
2350
2351 if( !dbus_type_is_basic(type) )
2352 goto EXIT;
2353
2354 if( !(sign = umdbus_arg_type_signature(type)) )
2355 goto EXIT;
2356
2357 DBusMessageIter var;
2358
2359 if( umdbus_open_container(iter, &var, DBUS_TYPE_VARIANT, sign) ) {
2360 ack = umdbus_append_basic_value(&var, DBUS_TYPE_BOOLEAN, val);
2361 ack = umdbus_close_container(iter, &var, ack);
2362 }
2363
2364EXIT:
2365
2366 if( !ack )
2367 log_warning("failed to append %s variant", umdbus_arg_type_repr(type));
2368
2369 return ack;
2370}
2371
2372bool
2373umdbus_append_bool(DBusMessageIter *iter, bool val)
2374{
2375 DBusBasicValue dta = { .bool_val = (dbus_bool_t)val };
2376 return umdbus_append_basic_value(iter, DBUS_TYPE_BOOLEAN, &dta);
2377}
2378
2379bool
2380umdbus_append_int(DBusMessageIter *iter, int val)
2381{
2382 DBusBasicValue dta = { .i32 = (dbus_int32_t)val };
2383 return umdbus_append_basic_value(iter, DBUS_TYPE_INT32, &dta);
2384}
2385
2386bool
2387umdbus_append_string(DBusMessageIter *iter, const char *val)
2388{
2389 DBusBasicValue dta = { .str = (char *)val };
2390 return umdbus_append_basic_value(iter, DBUS_TYPE_STRING, &dta);
2391}
2392
2393bool
2394umdbus_append_bool_variant(DBusMessageIter *iter, bool val)
2395{
2396 DBusBasicValue dta = { .bool_val = val };
2397 return umdbus_append_basic_variant(iter, DBUS_TYPE_BOOLEAN, &dta);
2398}
2399
2400bool
2401umdbus_append_int_variant(DBusMessageIter *iter, int val)
2402{
2403 DBusBasicValue dta = { .i32 = val };
2404 return umdbus_append_basic_variant(iter, DBUS_TYPE_INT32, &dta);
2405}
2406
2407bool
2408umdbus_append_string_variant(DBusMessageIter *iter, const char *val)
2409{
2410 DBusBasicValue dta = { .str = (char *)val };
2411 return umdbus_append_basic_variant(iter, DBUS_TYPE_STRING, &dta);
2412}
2413
2414bool
2415umdbus_append_args_va(DBusMessageIter *iter, int type, va_list va)
2416{
2417 bool ack = false;
2418
2419 DBusBasicValue *arg;
2420
2421 while( type != DBUS_TYPE_INVALID ) {
2422 switch( type ) {
2423 case DBUS_TYPE_VARIANT:
2424 type = va_arg(va, int);
2425 if( !dbus_type_is_basic(type) ) {
2426 log_err("variant type %s is not supported",
2427 umdbus_arg_type_repr(type));
2428 goto EXIT;
2429 }
2430 arg = va_arg(va, DBusBasicValue *);
2431 if( !umdbus_append_basic_variant(iter, type, arg) )
2432 goto EXIT;
2433
2434 break;
2435
2436 case DBUS_TYPE_ARRAY:
2437 case DBUS_TYPE_STRUCT:
2438 /* Not supported yet - fall through */
2439 default:
2440 if( !dbus_type_is_basic(type) ) {
2441 log_err("value type %s is not supported",
2442 umdbus_arg_type_repr(type));
2443 goto EXIT;
2444 }
2445 arg = va_arg(va, DBusBasicValue *);
2446 if( !umdbus_append_basic_value(iter, type, arg) )
2447 goto EXIT;
2448 break;
2449 }
2450 type = va_arg(va, int);
2451 }
2452 ack = true;
2453EXIT:
2454 return ack;
2455}
2456
2457bool
2458umdbus_append_args(DBusMessageIter *iter, int arg_type, ...)
2459{
2460 va_list va;
2461 va_start(va, arg_type);
2462 bool ack = umdbus_append_args_va(iter, arg_type, va);
2463 va_end(va);
2464 return ack;
2465}
2466
2467DBusMessage *
2468umdbus_blocking_call(DBusConnection *con,
2469 const char *dst,
2470 const char *obj,
2471 const char *iface,
2472 const char *meth,
2473 DBusError *err,
2474 int arg_type, ...)
2475{
2476 DBusMessage *rsp = 0;
2477 DBusMessage *req = 0;
2478 va_list va;
2479
2480 va_start(va, arg_type);
2481
2482 if( !(req = dbus_message_new_method_call(dst, obj, iface, meth)) )
2483 goto EXIT;
2484
2485 DBusMessageIter body;
2486 if( !umdbus_append_init(&body, req) )
2487 goto EXIT;
2488
2489 /* Note: Unlike dbus_message_append_args_valist():
2490 * - simple variants are supported
2491 * - arrays are not (yet)
2492 */
2493 if( !umdbus_append_args_va(&body, arg_type, va) )
2494 goto EXIT;
2495
2496 if( !(rsp = dbus_connection_send_with_reply_and_block(con, req, -1, err)) ) {
2497 log_warning("no reply to %s.%s(): %s: %s",
2498 iface, meth, err->name, err->message);
2499 goto EXIT;
2500 }
2501
2502 if( dbus_set_error_from_message(err, rsp) ) {
2503 log_warning("error reply to %s.%s(): %s: %s",
2504 iface, meth, err->name, err->message);
2505 dbus_message_unref(rsp), rsp = 0;
2506 goto EXIT;
2507 }
2508
2509 log_debug("blocking %s.%s() call succeeded", iface, meth);
2510
2511EXIT:
2512 if( req )
2513 dbus_message_unref(req);
2514
2515 va_end(va);
2516
2517 return rsp;
2518}
2519
2520bool
2521umdbus_parse_reply(DBusMessage *rsp, int arg_type, ...)
2522{
2523 bool ack = false;
2524 DBusError err = DBUS_ERROR_INIT;
2525 va_list va;
2526
2527 va_start(va, arg_type);
2528
2529 if( !rsp )
2530 goto EXIT;
2531
2532 /* Note: It is assumed that differentiation between replies and
2533 * error replies is done elsewhere.
2534 */
2535
2536 if( !dbus_message_get_args_valist(rsp, &err, arg_type, va) ) {
2537 log_warning("parse error: %s: %s", err.name, err.message);
2538 goto EXIT;
2539 }
2540
2541 ack = true;
2542
2543EXIT:
2544 dbus_error_free(&err);
2545
2546 va_end(va);
2547
2548 return ack;
2549}
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)
char * config_get_network_fallback(const char *config)
char * config_get_network_setting(const char *config)
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:669
const modedata_t * usbmoded_get_modedata(const char *modename)
Definition usb_moded.c:279
void usbmoded_probe_init_done(void)
Definition usb_moded.c:687