usb_moded  0.86.0+mer57
usb_moded-dbus.c
Go to the documentation of this file.
1 
35 #include "usb_moded-dbus-private.h"
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 
68 typedef struct umdbus_context_t umdbus_context_t;
69 
75 typedef struct {
77  int type;
78 
80  const char *member;
81 
83  void (*handler)(umdbus_context_t *);
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 
118 typedef struct
119 {
121  const char *interface;
122 
126 
129 typedef struct
130 {
132  const char *object;
133 
136 } object_info_t;
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 
182 static void member_info_introspect(const member_info_t *self, FILE *file);
183 
184 /* ------------------------------------------------------------------------- *
185  * INTERFACE_INFO
186  * ------------------------------------------------------------------------- */
187 
188 static const member_info_t *interface_info_get_member(const interface_info_t *self, const char *member);
189 static void interface_info_introspect(const interface_info_t *self, FILE *file);
190 
191 /* ------------------------------------------------------------------------- *
192  * OBJECT_INFO
193  * ------------------------------------------------------------------------- */
194 
195 static const interface_info_t *object_info_get_interface (const object_info_t *self, const char *interface);
196 static void object_info_introspect (const object_info_t *self, FILE *file, const char *interface);
197 static char *object_info_get_introspect_xml(const object_info_t *self, const char *interface);
198 
199 /* ------------------------------------------------------------------------- *
200  * INTROSPECTABLE
201  * ------------------------------------------------------------------------- */
202 
203 static void introspectable_introspect_cb(umdbus_context_t *context);
204 
205 /* ------------------------------------------------------------------------- *
206  * USB_MODED
207  * ------------------------------------------------------------------------- */
208 
209 static void usb_moded_state_request_cb (umdbus_context_t *context);
210 static void usb_moded_target_state_get_cb (umdbus_context_t *context);
211 static void usb_moded_target_config_get_cb (umdbus_context_t *context);
212 static void usb_moded_state_set_cb (umdbus_context_t *context);
213 static void usb_moded_config_set_cb (umdbus_context_t *context);
214 static void usb_moded_config_get_cb (umdbus_context_t *context);
215 static void usb_moded_mode_list_cb (umdbus_context_t *context);
216 static void usb_moded_available_modes_get_cb (umdbus_context_t *context);
217 static void usb_moded_available_modes_for_user_cb(umdbus_context_t *context);
218 static void usb_moded_mode_hide_cb (umdbus_context_t *context);
219 static void usb_moded_mode_unhide_cb (umdbus_context_t *context);
220 static void usb_moded_hidden_get_cb (umdbus_context_t *context);
221 static void usb_moded_whitelisted_modes_get_cb (umdbus_context_t *context);
222 static void usb_moded_whitelisted_modes_set_cb (umdbus_context_t *context);
223 static void usb_moded_user_config_clear_cb (umdbus_context_t *context);
224 static void usb_moded_whitelisted_set_cb (umdbus_context_t *context);
225 static void usb_moded_network_set_cb (umdbus_context_t *context);
226 static void usb_moded_network_get_cb (umdbus_context_t *context);
227 static void usb_moded_rescue_off_cb (umdbus_context_t *context);
228 
229 /* ------------------------------------------------------------------------- *
230  * UMDBUS
231  * ------------------------------------------------------------------------- */
232 
233 static const object_info_t *umdbus_get_object_info (const char *object);
234 void umdbus_dump_introspect_xml (void);
235 void umdbus_dump_busconfig_xml (void);
236 void umdbus_send_config_signal (const char *section, const char *key, const char *value);
237 static DBusHandlerResult umdbus_msg_handler (DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data);
238 DBusConnection *umdbus_get_connection (void);
239 gboolean umdbus_init_connection (void);
240 gboolean umdbus_init_service (void);
241 static void umdbus_cleanup_service (void);
242 void umdbus_cleanup (void);
243 static DBusMessage *umdbus_new_signal (const char *signal_name);
244 static int umdbus_send_signal_ex (const char *signal_name, const char *content);
245 static void umdbus_send_legacy_signal (const char *state_ind);
246 void umdbus_send_current_state_signal (const char *state_ind);
247 static bool umdbus_append_basic_entry (DBusMessageIter *iter, const char *key, int type, const void *val);
248 static bool umdbus_append_int32_entry (DBusMessageIter *iter, const char *key, int val);
249 static bool umdbus_append_string_entry (DBusMessageIter *iter, const char *key, const char *val);
250 static bool umdbus_append_mode_details (DBusMessage *msg, const char *mode_name);
251 static void umdbus_send_mode_details_signal (const char *mode_name);
252 void umdbus_send_target_state_signal (const char *state_ind);
253 void umdbus_send_event_signal (const char *state_ind);
254 int umdbus_send_error_signal (const char *error);
255 int umdbus_send_supported_modes_signal (const char *supported_modes);
256 int umdbus_send_available_modes_signal (const char *available_modes);
257 int umdbus_send_hidden_modes_signal (const char *hidden_modes);
258 int umdbus_send_whitelisted_modes_signal(const char *whitelist);
259 static void umdbus_get_name_owner_cb (DBusPendingCall *pc, void *aptr);
260 gboolean umdbus_get_name_owner_async (const char *name, usb_moded_get_name_owner_fn cb, DBusPendingCall **ppc);
261 static uid_t umdbus_get_sender_uid (const char *name);
262 const char *umdbus_arg_type_repr (int type);
263 const char *umdbus_arg_type_signature (int type);
264 const char *umdbus_msg_type_repr (int type);
265 bool umdbus_parser_init (DBusMessageIter *iter, DBusMessage *msg);
266 int umdbus_parser_at_type (DBusMessageIter *iter);
267 bool umdbus_parser_at_end (DBusMessageIter *iter);
268 bool umdbus_parser_require_type (DBusMessageIter *iter, int type, bool strict);
269 bool umdbus_parser_get_bool (DBusMessageIter *iter, bool *pval);
270 bool umdbus_parser_get_int (DBusMessageIter *iter, int *pval);
271 bool umdbus_parser_get_string (DBusMessageIter *iter, const char **pval);
272 bool umdbus_parser_get_object (DBusMessageIter *iter, const char **pval);
273 bool umdbus_parser_get_variant (DBusMessageIter *iter, DBusMessageIter *val);
274 bool umdbus_parser_get_array (DBusMessageIter *iter, DBusMessageIter *val);
275 bool umdbus_parser_get_struct (DBusMessageIter *iter, DBusMessageIter *val);
276 bool umdbus_parser_get_entry (DBusMessageIter *iter, DBusMessageIter *val);
277 bool umdbus_append_init (DBusMessageIter *iter, DBusMessage *msg);
278 bool umdbus_open_container (DBusMessageIter *iter, DBusMessageIter *sub, int type, const char *sign);
279 bool umdbus_close_container (DBusMessageIter *iter, DBusMessageIter *sub, bool success);
280 bool umdbus_append_basic_value (DBusMessageIter *iter, int type, const DBusBasicValue *val);
281 bool umdbus_append_basic_variant (DBusMessageIter *iter, int type, const DBusBasicValue *val);
282 bool umdbus_append_bool (DBusMessageIter *iter, bool val);
283 bool umdbus_append_int (DBusMessageIter *iter, int val);
284 bool umdbus_append_string (DBusMessageIter *iter, const char *val);
285 bool umdbus_append_bool_variant (DBusMessageIter *iter, bool val);
286 bool umdbus_append_int_variant (DBusMessageIter *iter, int val);
287 bool umdbus_append_string_variant (DBusMessageIter *iter, const char *val);
288 bool umdbus_append_args_va (DBusMessageIter *iter, int type, va_list va);
289 bool umdbus_append_args (DBusMessageIter *iter, int arg_type, ...);
290 DBusMessage *umdbus_blocking_call (DBusConnection *con, const char *dst, const char *obj, const char *iface, const char *meth, DBusError *err, int arg_type, ...);
291 bool umdbus_parse_reply (DBusMessage *rsp, int arg_type, ...);
292 
293 /* ========================================================================= *
294  * Data
295  * ========================================================================= */
296 
297 static DBusConnection *umdbus_connection = NULL;
298 static gboolean umdbus_service_name_acquired = FALSE;
299 
300 /* ========================================================================= *
301  * MEMBER_INFO
302  * ========================================================================= */
303 
304 static void
305 member_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 
335 static const member_info_t *
336 interface_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  }
351 EXIT:
352  return mem;
353 }
354 
355 static void
356 interface_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 
370 static const interface_info_t *
371 object_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  }
386 EXIT:
387  return ifc;
388 }
389 
390 static void
391 object_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");
433 EXIT:
434  return;
435 }
436 
437 static char *
438 object_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 
458 static void
459 introspectable_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 
469 static 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 
477 static 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 
486 static 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 
498 static 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 
513 static void
514 usb_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 
528 static void
529 usb_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 
540 static void
541 usb_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 
554 static void
555 usb_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 
611 static void
612 usb_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 
639 static void
640 usb_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 
658 static void
659 usb_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 
676 static void
677 usb_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 
690 static void
691 usb_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 
709 static void
710 usb_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 
742 static void
743 usb_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 
775 static void
776 usb_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 
794 static void
795 usb_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 
811 static void
812 usb_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 
836 static void
837 usb_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 
858 static void
859 usb_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 
885 static void
886 usb_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);
903  network_update();
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 
914 static void
915 usb_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 
946 static void
947 usb_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 
956 static 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"),
1051  ADD_SENTINEL
1052 };
1053 
1054 static const interface_info_t usb_moded_interface = {
1055  .interface = USB_MODE_INTERFACE,
1056  .members = usb_moded_members
1057 };
1058 
1059 /* ========================================================================= *
1060  * Functions
1061  * ========================================================================= */
1062 
1065 static const interface_info_t *standard_interfaces[] = {
1066  &introspectable_interface,
1067  &peer_interface,
1068  0
1069 };
1070 
1073 static const interface_info_t *usb_moded_interfaces[] = {
1074  &introspectable_interface,
1075  &peer_interface,
1076  &usb_moded_interface,
1077  0
1078 };
1079 
1082 static 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 
1110 static const object_info_t *
1111 umdbus_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 
1127 EXIT:
1128  return obj;
1129 }
1130 
1135 void
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 
1150 void
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 
1194 void 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 
1230 EXIT:
1231  if( msg )
1232  dbus_message_unref(msg);
1233 }
1234 
1235 static 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 */
1275  usbmoded_set_init_done(true);
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 
1311 EXIT:
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 
1324 DBusConnection *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 
1371 EXIT:
1372  dbus_error_free(&error);
1373  return status;
1374 }
1375 
1381 gboolean umdbus_init_service(void)
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 
1407 EXIT:
1408  dbus_error_free(&error);
1409  return status;
1410 }
1411 
1414 static 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 
1430 EXIT:
1431  return;
1432 }
1433 
1438 void umdbus_cleanup(void)
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 
1460 static DBusMessage*
1461 umdbus_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 
1486 EXIT:
1487  return msg;
1488 }
1489 
1498 static int
1499 umdbus_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 
1533 EXIT:
1534  // free the message
1535  if(msg != 0)
1536  dbus_message_unref(msg);
1537 
1538  return result;
1539 }
1540 
1548 static 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 
1559 void 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 
1577 static bool
1578 umdbus_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 
1619 bailout_variant:
1620  dbus_message_iter_abandon_container(&entry, &variant);
1621 
1622 bailout_entry:
1623  dbus_message_iter_abandon_container(iter, &entry);
1624 
1625 bailout_message:
1626  return false;
1627 }
1628 
1637 static bool
1638 umdbus_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 
1654 static bool
1655 umdbus_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 
1672 static bool
1673 umdbus_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 
1746 bailout_dict:
1747  dbus_message_iter_abandon_container(&body, &dict);
1748 
1749 bailout_message:
1750  return false;
1751 }
1752 
1757 static void
1758 umdbus_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 
1770 EXIT:
1771  if(msg != 0)
1772  dbus_message_unref(msg);
1773 }
1774 
1779 void 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 
1802 void 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 
1818 int 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 
1832 int 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 
1846 int 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 
1860 int 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 
1873 int umdbus_send_whitelisted_modes_signal(const char *whitelist)
1874 {
1875  LOG_REGISTER_CONTEXT;
1876 
1877  return umdbus_send_signal_ex(USB_MODE_WHITELISTED_MODES_SIGNAL_NAME, whitelist);
1878 }
1879 
1885 static 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 
1916 EXIT:
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 
1934 gboolean 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 
1977 EXIT:
1978 
1979  if( pc ) dbus_pending_call_unref(pc);
1980  if( req ) dbus_message_unref(req);
1981 
1982  return ack;
1983 }
1984 
1991 static uid_t
1992 umdbus_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 
2044 EXIT:
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 
2054 const char *
2055 umdbus_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 
2082 const char *
2083 umdbus_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 
2110 const char *
2111 umdbus_msg_type_repr(int type)
2112 {
2113  return dbus_message_type_to_string(type);
2114 }
2115 
2116 bool
2117 umdbus_parser_init(DBusMessageIter *iter, DBusMessage *msg)
2118 {
2119  return iter && msg && dbus_message_iter_init(msg, iter);
2120 }
2121 
2122 int
2123 umdbus_parser_at_type(DBusMessageIter *iter)
2124 {
2125  return iter ? dbus_message_iter_get_arg_type(iter) : DBUS_TYPE_INVALID;
2126 }
2127 
2128 bool
2129 umdbus_parser_at_end(DBusMessageIter *iter)
2130 {
2131  return umdbus_parser_at_type(iter) == DBUS_TYPE_INVALID;
2132 }
2133 
2134 bool
2135 umdbus_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 
2149 bool
2150 umdbus_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 
2161 bool
2162 umdbus_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 
2173 bool
2174 umdbus_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 
2185 bool
2186 umdbus_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 
2197 bool
2198 umdbus_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 
2208 bool
2209 umdbus_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 
2219 bool
2220 umdbus_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 
2230 bool
2231 umdbus_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 
2241 bool
2242 umdbus_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 
2248 bool
2249 umdbus_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 
2263 bool
2264 umdbus_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 
2278 bool
2279 umdbus_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 
2339 bool
2340 umdbus_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 
2360 EXIT:
2361 
2362  if( !ack )
2363  log_warning("failed to append %s variant", umdbus_arg_type_repr(type));
2364 
2365  return ack;
2366 }
2367 
2368 bool
2369 umdbus_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 
2375 bool
2376 umdbus_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 
2382 bool
2383 umdbus_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 
2389 bool
2390 umdbus_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 
2396 bool
2397 umdbus_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 
2403 bool
2404 umdbus_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 
2410 bool
2411 umdbus_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;
2449 EXIT:
2450  return ack;
2451 }
2452 
2453 bool
2454 umdbus_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 
2463 DBusMessage *
2464 umdbus_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 
2507 EXIT:
2508  if( req )
2509  dbus_message_unref(req);
2510 
2511  va_end(va);
2512 
2513  return rsp;
2514 }
2515 
2516 bool
2517 umdbus_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 
2539 EXIT:
2540  dbus_error_free(&err);
2541 
2542  va_end(va);
2543 
2544  return ack;
2545 }
config_user_clear
bool config_user_clear(uid_t uid)
Definition: usb_moded-config.c:1123
USB_MODE_SERVICE
#define USB_MODE_SERVICE
Definition: usb_moded-dbus.h:42
usb_moded-dbus-private.h
usb_moded-modes.h
MODE_BUSY
#define MODE_BUSY
Definition: usb_moded-modes.h:57
umdbus_send_current_state_signal
void umdbus_send_current_state_signal(const char *state_ind)
Definition: usb_moded-dbus.c:1559
member_info_t::member
const char * member
Definition: usb_moded-dbus.c:80
umdbus_send_error_signal
int umdbus_send_error_signal(const char *error)
Definition: usb_moded-dbus.c:1818
umdbus_send_available_modes_signal
int umdbus_send_available_modes_signal(const char *available_modes)
Definition: usb_moded-dbus.c:1846
umdbus_send_config_signal
void umdbus_send_config_signal(const char *section, const char *key, const char *value)
Definition: usb_moded-dbus.c:1194
member_info_t::args
const char * args
Definition: usb_moded-dbus.c:86
AVAILABLE_MODES_LIST
@ AVAILABLE_MODES_LIST
Definition: usb_moded-common.h:45
umdbus_send_event_signal
void umdbus_send_event_signal(const char *state_ind)
Definition: usb_moded-dbus.c:1802
umdbus_context_t::type
int type
Definition: usb_moded-dbus.c:147
MODE_CHARGING_FALLBACK
#define MODE_CHARGING_FALLBACK
Definition: usb_moded-modes.h:67
usb_moded-dbus.h
umdbus_context_t::msg
DBusMessage * msg
Definition: usb_moded-dbus.c:144
usb_moded-network.h
umdbus_context_t::member_info
const member_info_t * member_info
Definition: usb_moded-dbus.c:168
umdbus_dump_introspect_xml
void umdbus_dump_introspect_xml(void)
Definition: usb_moded-dbus.c:1136
umdbus_send_hidden_modes_signal
int umdbus_send_hidden_modes_signal(const char *hidden_modes)
Definition: usb_moded-dbus.c:1860
umdbus_context_t::object
const char * object
Definition: usb_moded-dbus.c:153
usb_moded-config-private.h
umdbus_send_whitelisted_modes_signal
int umdbus_send_whitelisted_modes_signal(const char *whitelist)
Definition: usb_moded-dbus.c:1873
umdbus_get_name_owner_async
gboolean umdbus_get_name_owner_async(const char *name, usb_moded_get_name_owner_fn cb, DBusPendingCall **ppc)
Definition: usb_moded-dbus.c:1934
usb_moded.h
umdbus_context_t::interface_info
const interface_info_t * interface_info
Definition: usb_moded-dbus.c:165
usbmoded_get_modedata
const modedata_t * usbmoded_get_modedata(const char *modename)
Definition: usb_moded.c:252
common_valid_mode
int common_valid_mode(const char *mode)
Definition: usb_moded-common.c:535
interface_info_t::members
const member_info_t * members
Definition: usb_moded-dbus.c:124
umdbus_context_t::sender
const char * sender
Definition: usb_moded-dbus.c:150
umdbus_context_t
Definition: usb_moded-dbus.c:142
object_info_t::object
const char * object
Definition: usb_moded-dbus.c:132
usb_moded-control.h
interface_info_t::interface
const char * interface
Definition: usb_moded-dbus.c:121
member_info_t::handler
void(* handler)(umdbus_context_t *)
Definition: usb_moded-dbus.c:83
umdbus_init_connection
gboolean umdbus_init_connection(void)
Definition: usb_moded-dbus.c:1341
umdbus_init_service
gboolean umdbus_init_service(void)
Definition: usb_moded-dbus.c:1381
member_info_t::type
int type
Definition: usb_moded-dbus.c:77
umdbus_cleanup
void umdbus_cleanup(void)
Definition: usb_moded-dbus.c:1438
umdbus_context_t::rsp
DBusMessage * rsp
Definition: usb_moded-dbus.c:171
interface_info_t
Definition: usb_moded-dbus.c:118
DBUS_GET_NAME_OWNER_REQ
#define DBUS_GET_NAME_OWNER_REQ
Definition: usb_moded-dbus-private.h:45
object_info_t
Definition: usb_moded-dbus.c:129
common_get_mode_list
gchar * common_get_mode_list(mode_list_type_t type, uid_t uid)
Definition: usb_moded-common.c:574
ADD_SIGNAL
#define ADD_SIGNAL(NAME, ARGS)
Definition: usb_moded-dbus.c:100
DBUS_GET_CONNECTION_PID_REQ
#define DBUS_GET_CONNECTION_PID_REQ
Definition: usb_moded-dbus-private.h:51
umdbus_send_supported_modes_signal
int umdbus_send_supported_modes_signal(const char *supported_modes)
Definition: usb_moded-dbus.c:1832
umdbus_context_t::object_info
const object_info_t * object_info
Definition: usb_moded-dbus.c:162
usbmoded_probe_init_done
void usbmoded_probe_init_done(void)
Definition: usb_moded.c:651
ADD_SENTINEL
#define ADD_SENTINEL
Definition: usb_moded-dbus.c:109
control_select_mode
bool control_select_mode(const char *mode)
Definition: usb_moded-control.c:307
usb_moded-log.h
USB_MODE_SIGNAL_NAME
#define USB_MODE_SIGNAL_NAME
Definition: usb_moded-dbus.h:52
modedata_t
Definition: usb_moded-dyn-config.h:100
member_info_t
Definition: usb_moded-dbus.c:75
SUPPORTED_MODES_LIST
@ SUPPORTED_MODES_LIST
Definition: usb_moded-common.h:43
MODE_CHARGING
#define MODE_CHARGING
Definition: usb_moded-modes.h:77
control_get_cable_state
cable_state_t control_get_cable_state(void)
Definition: usb_moded-control.c:846
ADD_METHOD
#define ADD_METHOD(NAME, FUNC, ARGS)
Definition: usb_moded-dbus.c:91
umdbus_context_t::member
const char * member
Definition: usb_moded-dbus.c:159
log_p
bool log_p(int lev)
Definition: usb_moded-log.c:347
object_info_t::interfaces
const interface_info_t ** interfaces
Definition: usb_moded-dbus.c:135
network_update
void network_update(void)
Definition: usb_moded-network.c:1221
usbmoded_set_init_done
void usbmoded_set_init_done(bool reached)
Definition: usb_moded.c:633
umdbus_context_t::interface
const char * interface
Definition: usb_moded-dbus.c:156
umdbus_dump_busconfig_xml
void umdbus_dump_busconfig_xml(void)
Definition: usb_moded-dbus.c:1151
umdbus_send_target_state_signal
void umdbus_send_target_state_signal(const char *state_ind)
Definition: usb_moded-dbus.c:1779