usb_moded 0.86.0+mer64
usb_moded-devicelock.c
Go to the documentation of this file.
1
31
32/*
33 * Interacts with the devicelock to know if we can expose the system contents or not
34 */
35
37
38#include "usb_moded-control.h"
40#include "usb_moded-log.h"
41
42/* ========================================================================= *
43 * Types
44 * ========================================================================= */
45
58
59/* ========================================================================= *
60 * Prototypes
61 * ========================================================================= */
62
63/* ------------------------------------------------------------------------- *
64 * DEVICELOCK
65 * ------------------------------------------------------------------------- */
66
67static const char *devicelock_state_repr (devicelock_state_t state);
69static void devicelock_state_changed (devicelock_state_t state);
70static void devicelock_state_cancel (void);
71static void devicelock_state_query_cb (DBusPendingCall *pending, void *aptr);
72static void devicelock_state_query (void);
73static void devicelock_state_signal (DBusMessage *msg);
74static void devicelock_available_changed (const char *owner);
75static void devicelock_available_cb (const char *owner);
76static void devicelock_available_cancel (void);
77static void devicelock_available_query (void);
78static void devicelock_name_owner_signal (DBusMessage *msg);
79static DBusHandlerResult devicelock_dbus_filter_cb (DBusConnection *con, DBusMessage *msg, void *aptr);
80bool devicelock_start_listener (void);
81void devicelock_stop_listener (void);
82
83/* ========================================================================= *
84 * module state data
85 * ========================================================================= */
86
87/* SystemBus connection ref used for devicelock ipc */
88static DBusConnection *devicelock_con = NULL;
89
90/* Cached devicelock state */
91static devicelock_state_t devicelock_state = DEVICELOCK_UNDEFINED;
92
93/* Flag for: devicelock is available on system bus */
94static gboolean devicelock_is_available = FALSE;
95
96/* ========================================================================= *
97 * devicelock state type
98 * ========================================================================= */
99
102static const char *
103devicelock_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
142static 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
156EXIT:
157 return;
158}
159
160static DBusPendingCall *devicelock_state_query_pc = 0;
161
162static 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
173static 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
207EXIT:
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
218static 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
257EXIT:
258
259 if( pc ) dbus_pending_call_unref(pc);
260 if( req ) dbus_message_unref(req);
261}
262
263static 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
288static 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
309static DBusPendingCall *devicelock_available_pc = 0;
310
311static 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
321static 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
333static 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
346static 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
375static DBusHandlerResult
376devicelock_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
403bool
404devicelock_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
436cleanup:
437
438 return ack;
439}
440
441void
442devicelock_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}
void control_device_lock_changed(void)
#define DBUS_NAME_OWNER_CHANGED_SIG
gboolean umdbus_get_name_owner_async(const char *name, usb_moded_get_name_owner_fn cb, DBusPendingCall **ppc)
devicelock_state_t
@ DEVICELOCK_UNDEFINED
@ DEVICELOCK_UNLOCKED
@ DEVICELOCK_LOCKED
bool devicelock_have_export_permission(void)