usb_moded  0.86.0+mer57
usb_moded-devicelock.c
Go to the documentation of this file.
1 
32 /*
33  * Interacts with the devicelock to know if we can expose the system contents or not
34  */
35 
36 #include "usb_moded-devicelock.h"
37 
38 #include "usb_moded-control.h"
39 #include "usb_moded-dbus-private.h"
40 #include "usb_moded-log.h"
41 
42 /* ========================================================================= *
43  * Types
44  * ========================================================================= */
45 
47 typedef enum devicelock_state_t
48 {
51 
54 
58 
59 /* ========================================================================= *
60  * Prototypes
61  * ========================================================================= */
62 
63 /* ------------------------------------------------------------------------- *
64  * DEVICELOCK
65  * ------------------------------------------------------------------------- */
66 
67 static const char *devicelock_state_repr (devicelock_state_t state);
69 static void devicelock_state_changed (devicelock_state_t state);
70 static void devicelock_state_cancel (void);
71 static void devicelock_state_query_cb (DBusPendingCall *pending, void *aptr);
72 static void devicelock_state_query (void);
73 static void devicelock_state_signal (DBusMessage *msg);
74 static void devicelock_available_changed (const char *owner);
75 static void devicelock_available_cb (const char *owner);
76 static void devicelock_available_cancel (void);
77 static void devicelock_available_query (void);
78 static void devicelock_name_owner_signal (DBusMessage *msg);
79 static DBusHandlerResult devicelock_dbus_filter_cb (DBusConnection *con, DBusMessage *msg, void *aptr);
80 bool devicelock_start_listener (void);
81 void devicelock_stop_listener (void);
82 
83 /* ========================================================================= *
84  * module state data
85  * ========================================================================= */
86 
87 /* SystemBus connection ref used for devicelock ipc */
88 static DBusConnection *devicelock_con = NULL;
89 
90 /* Cached devicelock state */
91 static devicelock_state_t devicelock_state = DEVICELOCK_UNDEFINED;
92 
93 /* Flag for: devicelock is available on system bus */
94 static gboolean devicelock_is_available = FALSE;
95 
96 /* ========================================================================= *
97  * devicelock state type
98  * ========================================================================= */
99 
102 static const char *
103 devicelock_state_repr(devicelock_state_t state)
104 {
105  LOG_REGISTER_CONTEXT;
106 
107  const char *repr = "DEVICELOCK_<INVALID>";
108 
109  switch( state )
110  {
111  case DEVICELOCK_UNLOCKED: repr = "DEVICELOCK_UNLOCKED"; break;
112  case DEVICELOCK_LOCKED: repr = "DEVICELOCK_LOCKED"; break;
113  case DEVICELOCK_UNDEFINED: repr = "DEVICELOCK_UNDEFINED"; break;
114  default: break;
115  }
116 
117  return repr;
118 }
119 
120 /* ========================================================================= *
121  * functionality provided to the other modules
122  * ========================================================================= */
123 
130 {
131  LOG_REGISTER_CONTEXT;
132 
133  bool unlocked = (devicelock_state == DEVICELOCK_UNLOCKED);
134 
135  return unlocked;
136 }
137 
138 /* ========================================================================= *
139  * devicelock state queries
140  * ========================================================================= */
141 
142 static void devicelock_state_changed(devicelock_state_t state)
143 {
144  LOG_REGISTER_CONTEXT;
145 
146  if( devicelock_state == state )
147  goto EXIT;
148 
149  log_debug("devicelock state: %s -> %s",
150  devicelock_state_repr(devicelock_state),
151  devicelock_state_repr(state));
152  devicelock_state = state;
153 
155 
156 EXIT:
157  return;
158 }
159 
160 static DBusPendingCall *devicelock_state_query_pc = 0;
161 
162 static void devicelock_state_cancel(void)
163 {
164  LOG_REGISTER_CONTEXT;
165 
166  if( devicelock_state_query_pc ) {
167  dbus_pending_call_cancel(devicelock_state_query_pc);
168  dbus_pending_call_unref(devicelock_state_query_pc),
169  devicelock_state_query_pc = 0;
170  }
171 }
172 
173 static void devicelock_state_query_cb(DBusPendingCall *pending, void *aptr)
174 {
175  LOG_REGISTER_CONTEXT;
176 
177  DBusMessage *rsp = 0;
178  dbus_int32_t dta = DEVICELOCK_UNDEFINED;
179  DBusError err = DBUS_ERROR_INIT;
180 
181  (void)aptr;
182 
183  if( !(rsp = dbus_pending_call_steal_reply(pending)) )
184  {
185  log_err("%s.%s: no reply",
186  DEVICELOCK_INTERFACE, DEVICELOCK_GET_STATE_REQ);
187  goto EXIT;
188  }
189 
190  if( dbus_set_error_from_message(&err, rsp) )
191  {
192  log_err("%s.%s: error reply: %s: %s",
193  DEVICELOCK_INTERFACE, DEVICELOCK_GET_STATE_REQ,
194  err.name, err.message);
195  goto EXIT;
196  }
197 
198  if( !dbus_message_get_args(rsp, &err, DBUS_TYPE_INT32, &dta,
199  DBUS_TYPE_INVALID) )
200  {
201  log_err("%s.%s: parse error: %s: %s",
202  DEVICELOCK_INTERFACE, DEVICELOCK_GET_STATE_REQ,
203  err.name, err.message);
204  goto EXIT;
205  }
206 
207 EXIT:
208  devicelock_state_changed(dta);
209 
210  if( rsp ) dbus_message_unref(rsp);
211 
212  dbus_error_free(&err);
213 
214  dbus_pending_call_unref(devicelock_state_query_pc),
215  devicelock_state_query_pc = 0;
216 }
217 
218 static void devicelock_state_query(void)
219 {
220  LOG_REGISTER_CONTEXT;
221 
222  DBusMessage *req = NULL;
223  DBusPendingCall *pc = 0;
224 
225  devicelock_state_cancel();
226 
227  log_debug("querying device lock state");
228 
229  if( !devicelock_con ) {
230  log_err("not connected to system bus; skip device state query");
231  goto EXIT;
232  }
233 
234  req = dbus_message_new_method_call(DEVICELOCK_SERVICE,
235  DEVICELOCK_OBJECT,
236  DEVICELOCK_INTERFACE,
237  DEVICELOCK_GET_STATE_REQ);
238 
239  if( !req )
240  {
241  log_err("%s.%s: failed to construct request",
242  DEVICELOCK_INTERFACE, DEVICELOCK_GET_STATE_REQ);
243  goto EXIT;
244  }
245 
246  if( !dbus_connection_send_with_reply(devicelock_con, req, &pc, -1) )
247  goto EXIT;
248 
249  if( !pc )
250  goto EXIT;
251 
252  if( !dbus_pending_call_set_notify(pc, devicelock_state_query_cb, 0, 0) )
253  goto EXIT;
254 
255  devicelock_state_query_pc = pc, pc = 0;
256 
257 EXIT:
258 
259  if( pc ) dbus_pending_call_unref(pc);
260  if( req ) dbus_message_unref(req);
261 }
262 
263 static void devicelock_state_signal(DBusMessage *msg)
264 {
265  LOG_REGISTER_CONTEXT;
266 
267  DBusError err = DBUS_ERROR_INIT;
268  dbus_int32_t dta = DEVICELOCK_LOCKED;
269 
270  if( !dbus_message_get_args(msg, &err,
271  DBUS_TYPE_INT32, &dta,
272  DBUS_TYPE_INVALID) )
273  {
274  log_err("failed to parse %s.%s signal: %s: %s",
275  DEVICELOCK_INTERFACE, DEVICELOCK_STATE_CHANGED_SIG,
276  err.name, err.message);
277  }
278 
279  devicelock_state_changed(dta);
280 
281  dbus_error_free(&err);
282 }
283 
284 /* ========================================================================= *
285  * devicelock name owner tracking
286  * ========================================================================= */
287 
288 static void devicelock_available_changed(const char *owner)
289 {
290  LOG_REGISTER_CONTEXT;
291 
292  gboolean is_available = (owner && *owner);
293 
294  if( devicelock_is_available != is_available ) {
295  devicelock_is_available = is_available;
296  log_debug("devicelock is %s",
297  devicelock_is_available ? "running" : "stopped");
298 
299  /* Forget cached device state */
300  devicelock_state_changed(DEVICELOCK_UNDEFINED);
301 
302  /* Query current state on devicelock startup */
303  if( devicelock_is_available ) {
304  devicelock_state_query();
305  }
306  }
307 }
308 
309 static DBusPendingCall *devicelock_available_pc = 0;
310 
311 static void devicelock_available_cb(const char *owner)
312 {
313  LOG_REGISTER_CONTEXT;
314 
315  devicelock_available_changed(owner);
316 
317  dbus_pending_call_unref(devicelock_available_pc),
318  devicelock_available_pc = 0;
319 }
320 
321 static void devicelock_available_cancel(void)
322 {
323  LOG_REGISTER_CONTEXT;
324 
325  if( devicelock_available_pc )
326  {
327  dbus_pending_call_cancel(devicelock_available_pc);
328  dbus_pending_call_unref(devicelock_available_pc),
329  devicelock_available_pc = 0;
330  }
331 }
332 
333 static void devicelock_available_query(void)
334 {
335  LOG_REGISTER_CONTEXT;
336 
337  devicelock_available_cancel();
338 
339  log_debug("querying %s name owner", DEVICELOCK_SERVICE);
340 
341  umdbus_get_name_owner_async(DEVICELOCK_SERVICE,
342  devicelock_available_cb,
343  &devicelock_available_pc);
344 }
345 
346 static void devicelock_name_owner_signal(DBusMessage *msg)
347 {
348  LOG_REGISTER_CONTEXT;
349 
350  DBusError err = DBUS_ERROR_INIT;
351  const char *name = 0;
352  const char *prev = 0;
353  const char *curr = 0;
354 
355  if( !dbus_message_get_args(msg, &err,
356  DBUS_TYPE_STRING, &name,
357  DBUS_TYPE_STRING, &prev,
358  DBUS_TYPE_STRING, &curr,
359  DBUS_TYPE_INVALID) )
360  {
361  log_err("failed to parse signal: %s: %s",
362  err.name, err.message);
363  }
364  else if( !strcmp(name, DEVICELOCK_SERVICE) )
365  {
366  devicelock_available_changed(curr);
367  }
368  dbus_error_free(&err);
369 }
370 
371 /* ========================================================================= *
372  * dbus message filter
373  * ========================================================================= */
374 
375 static DBusHandlerResult
376 devicelock_dbus_filter_cb(DBusConnection *con, DBusMessage *msg, void *aptr)
377 {
378  LOG_REGISTER_CONTEXT;
379 
380  (void)con;
381  (void)aptr;
382 
383  if( dbus_message_is_signal(msg,
384  DEVICELOCK_INTERFACE,
385  DEVICELOCK_STATE_CHANGED_SIG) )
386  {
387  devicelock_state_signal(msg);
388  }
389  else if( dbus_message_is_signal(msg,
390  DBUS_INTERFACE_DBUS,
392  {
393  devicelock_name_owner_signal(msg);
394  }
395 
396  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
397 }
398 
399 /* ========================================================================= *
400  * start/stop devicelock state tracking
401  * ========================================================================= */
402 
403 bool
404 devicelock_start_listener(void)
405 {
406  LOG_REGISTER_CONTEXT;
407 
408  bool ack = false;
409 
410  log_debug("starting devicelock listener");
411 
412  /* Get connection ref */
413  if( (devicelock_con = umdbus_get_connection()) == 0 )
414  {
415  log_err("Could not connect to dbus for devicelock\n");
416  goto cleanup;
417  }
418 
419  /* Add filter callback */
420  if( !dbus_connection_add_filter(devicelock_con,
421  devicelock_dbus_filter_cb , 0, 0) )
422  {
423  log_err("adding system dbus filter for devicelock failed");
424  goto cleanup;
425  }
426 
427  /* Add match without blocking / error checking */
428  dbus_bus_add_match(devicelock_con, DEVICELOCK_STATE_CHANGED_MATCH,0);
429  dbus_bus_add_match(devicelock_con, DEVICELOCK_NAME_OWNER_CHANGED_MATCH,0);
430 
431  /* Initiate async devicelock name owner query */
432  devicelock_available_query();
433 
434  ack = true;
435 
436 cleanup:
437 
438  return ack;
439 }
440 
441 void
442 devicelock_stop_listener(void)
443 {
444  LOG_REGISTER_CONTEXT;
445 
446  log_debug("stopping devicelock listener");
447 
448  /* Do note leave pending queries behind */
449  devicelock_state_cancel();
450  devicelock_available_cancel();
451 
452  if(devicelock_con)
453  {
454  /* Remove filter callback */
455  dbus_connection_remove_filter(devicelock_con,
456  devicelock_dbus_filter_cb, 0);
457 
458  if( dbus_connection_get_is_connected(devicelock_con) ) {
459  /* Remove match without blocking / error checking */
460  dbus_bus_remove_match(devicelock_con,
461  DEVICELOCK_STATE_CHANGED_MATCH, 0);
462  dbus_bus_remove_match(devicelock_con,
463  DEVICELOCK_NAME_OWNER_CHANGED_MATCH, 0);
464  }
465 
466  /* Let go of connection ref */
467  dbus_connection_unref(devicelock_con),
468  devicelock_con = 0;
469  }
470 }
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-dbus-private.h
devicelock_state_t
devicelock_state_t
Definition: usb_moded-devicelock.c:47
usb_moded-control.h
DBUS_NAME_OWNER_CHANGED_SIG
#define DBUS_NAME_OWNER_CHANGED_SIG
Definition: usb_moded-dbus-private.h:48
control_device_lock_changed
void control_device_lock_changed(void)
Definition: usb_moded-control.c:473
devicelock_have_export_permission
bool devicelock_have_export_permission(void)
Definition: usb_moded-devicelock.c:129
usb_moded-log.h
DEVICELOCK_LOCKED
@ DEVICELOCK_LOCKED
Definition: usb_moded-devicelock.c:53
usb_moded-devicelock.h
DEVICELOCK_UNLOCKED
@ DEVICELOCK_UNLOCKED
Definition: usb_moded-devicelock.c:50
DEVICELOCK_UNDEFINED
@ DEVICELOCK_UNDEFINED
Definition: usb_moded-devicelock.c:56