usb_moded 0.86.0+mer58
usb_moded-common.c
Go to the documentation of this file.
1
26
27#include "usb_moded-common.h"
28
29#include "usb_moded.h"
32#include "usb_moded-log.h"
33#include "usb_moded-modes.h"
34#include "usb_moded-worker.h"
35
36#include <sys/wait.h>
37
38#include <unistd.h>
39#include <fcntl.h>
40
41/* ========================================================================= *
42 * Types
43 * ========================================================================= */
44
46typedef struct modemapping_t
47{
49 const char *internal_mode;
50
52 const char *hardware_mode;
53
55 const char *external_mode;
57
58/* ========================================================================= *
59 * Prototypes
60 * ========================================================================= */
61
62/* ------------------------------------------------------------------------- *
63 * CABLE_STATE
64 * ------------------------------------------------------------------------- */
65
66const char *cable_state_repr(cable_state_t state);
67
68/* ------------------------------------------------------------------------- *
69 * COMMON
70 * ------------------------------------------------------------------------- */
71
72const char *common_map_mode_to_hardware (const char *internal_mode);
73const char *common_map_mode_to_external (const char *internal_mode);
78static void common_write_to_sysfs_file (const char *path, const char *text);
79void common_acquire_wakelock (const char *wakelock_name);
80void common_release_wakelock (const char *wakelock_name);
81int common_system_ (const char *file, int line, const char *func, const char *command);
82FILE *common_popen_ (const char *file, int line, const char *func, const char *command, const char *type);
83waitres_t common_wait (unsigned tot_ms, bool (*ready_cb)(void *aptr), void *aptr);
84bool common_msleep_ (const char *file, int line, const char *func, unsigned msec);
85static bool common_mode_in_list (const char *mode, char *const *modes);
86bool common_modename_is_internal (const char *modename);
87bool common_modename_is_static (const char *modename);
88int common_valid_mode (const char *mode);
89gchar *common_get_mode_list (mode_list_type_t type, uid_t uid);
90
91/* ========================================================================= *
92 * Functions
93 * ========================================================================= */
94
95/* ------------------------------------------------------------------------- *
96 * CABLE_STATE
97 * ------------------------------------------------------------------------- */
98
99const char *cable_state_repr(cable_state_t state)
100{
101 LOG_REGISTER_CONTEXT;
102
103 static const char * const lut[CABLE_STATE_NUMOF] = {
104 [CABLE_STATE_UNKNOWN] = "unknown",
105 [CABLE_STATE_DISCONNECTED] = "disconnected",
106 [CABLE_STATE_CHARGER_CONNECTED] = "charger_connected",
107 [CABLE_STATE_PC_CONNECTED] = "pc_connected",
108 };
109 return lut[state];
110}
111
112/* ------------------------------------------------------------------------- *
113 * MODE_MAPPING
114 * ------------------------------------------------------------------------- */
115
116static const modemapping_t common_modemapping[] =
117{
118 {
119 .internal_mode = MODE_UNDEFINED,
120 .hardware_mode = MODE_CHARGING,
121 .external_mode = 0,
122 },
123 {
124 .internal_mode = MODE_ASK,
125 .hardware_mode = MODE_CHARGING,
126 .external_mode = 0,
127 },
128 {
129 .internal_mode = MODE_MASS_STORAGE,
130 .hardware_mode = 0,
131 .external_mode = 0,
132 },
133 {
134 .internal_mode = MODE_DEVELOPER,
135 .hardware_mode = 0,
136 .external_mode = 0,
137 },
138 {
139 .internal_mode = MODE_MTP,
140 .hardware_mode = 0,
141 .external_mode = 0,
142 },
143 {
144 .internal_mode = MODE_HOST,
145 .hardware_mode = 0,
146 .external_mode = 0,
147 },
148 {
149 .internal_mode = MODE_CONNECTION_SHARING,
150 .hardware_mode = 0,
151 .external_mode = 0,
152 },
153 {
154 .internal_mode = MODE_DIAG,
155 .hardware_mode = 0,
156 .external_mode = 0,
157 },
158 {
159 .internal_mode = MODE_ADB,
160 .hardware_mode = 0,
161 .external_mode = 0,
162 },
163 {
164 .internal_mode = MODE_PC_SUITE,
165 .hardware_mode = 0,
166 .external_mode = 0,
167 },
168 {
169 .internal_mode = MODE_CHARGING,
170 .hardware_mode = MODE_CHARGING,
171 .external_mode = 0,
172 },
173 {
174 .internal_mode = MODE_CHARGING_FALLBACK,
175 .hardware_mode = MODE_CHARGING,
176 .external_mode = 0,
177 },
178 {
179 .internal_mode = MODE_CHARGER,
180 .hardware_mode = MODE_CHARGING,
181 .external_mode = 0,
182 },
183 // sentinel
184 {
185 .internal_mode = 0,
186 .hardware_mode = 0,
187 .external_mode = 0,
188 }
189};
190
191const char *
192common_map_mode_to_hardware(const char *internal_mode)
193{
194 LOG_REGISTER_CONTEXT;
195
196 const char *hardware_mode = 0;
197
198 for( size_t i = 0; common_modemapping[i].internal_mode; ++i ) {
199 if( strcmp(common_modemapping[i].internal_mode, internal_mode) )
200 continue;
201 hardware_mode = common_modemapping[i].hardware_mode;
202 break;
203 }
204 return hardware_mode ?: internal_mode;
205}
206
207const char *
208common_map_mode_to_external(const char *internal_mode)
209{
210 LOG_REGISTER_CONTEXT;
211
212 const char *external_mode = 0;
213
214 for( size_t i = 0; common_modemapping[i].internal_mode; ++i ) {
215 if( strcmp(common_modemapping[i].internal_mode, internal_mode) )
216 continue;
217 external_mode = common_modemapping[i].external_mode;
218 break;
219 }
220 return external_mode ?: internal_mode;
221}
222
223/* ------------------------------------------------------------------------- *
224 * DBUS_NOTIFICATIONS
225 * ------------------------------------------------------------------------- */
226
230{
231 LOG_REGISTER_CONTEXT;
232
233 gchar *mode_list = common_get_mode_list(SUPPORTED_MODES_LIST, 0);
235 g_free(mode_list);
236}
237
241{
242 LOG_REGISTER_CONTEXT;
243
244 gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST, 0);
246 g_free(mode_list);
247}
248
252{
253 LOG_REGISTER_CONTEXT;
254
255 gchar *mode_list = config_get_hidden_modes();
257 g_free(mode_list);
258}
259
263{
264 LOG_REGISTER_CONTEXT;
265
266 gchar *mode_list = config_get_mode_whitelist();
268 g_free(mode_list);
269}
270
271/* ------------------------------------------------------------------------- *
272 * SYSFS_IO
273 * ------------------------------------------------------------------------- */
274
282static void common_write_to_sysfs_file(const char *path, const char *text)
283{
284 LOG_REGISTER_CONTEXT;
285
286 int fd = -1;
287
288 if (!path || !text)
289 goto EXIT;
290
291 if ((fd = open(path, O_WRONLY)) == -1) {
292 if (errno != ENOENT) {
293 log_warning("%s: open for writing failed: %m", path);
294 }
295 goto EXIT;
296 }
297
298 if (write(fd, text, strlen(text)) == -1) {
299 log_warning("%s: write failed : %m", path);
300 goto EXIT;
301 }
302EXIT:
303 if (fd != -1)
304 close(fd);
305}
306
307/* ------------------------------------------------------------------------- *
308 * WAKELOCKS
309 * ------------------------------------------------------------------------- */
310
323void common_acquire_wakelock(const char *wakelock_name)
324{
325 LOG_REGISTER_CONTEXT;
326
327 char buff[256];
328 snprintf(buff, sizeof buff, "%s %lld",
329 wakelock_name,
331 common_write_to_sysfs_file("/sys/power/wake_lock", buff);
332
333#if VERBOSE_WAKELOCKING
334 log_debug("common_acquire_wakelock %s", wakelock_name);
335#endif
336}
337
342void common_release_wakelock(const char *wakelock_name)
343{
344 LOG_REGISTER_CONTEXT;
345
346#if VERBOSE_WAKELOCKING
347 log_debug("common_release_wakelock %s", wakelock_name);
348#endif
349
350 common_write_to_sysfs_file("/sys/power/wake_unlock", wakelock_name);
351}
352
353/* ------------------------------------------------------------------------- *
354 * BLOCKING_OPERATION
355 * ------------------------------------------------------------------------- */
356
359int
360common_system_(const char *file, int line, const char *func,
361 const char *command)
362{
363 LOG_REGISTER_CONTEXT;
364
365 int result = -1;
366 int status = -1;
367 char exited[32] = "";
368 char trapped[32] = "";
369 const char *dumped = "";
370
371 log_debug("EXEC %s; from %s:%d: %s()", command, file, line, func);
372
373 if( (status = system(command)) == -1 ) {
374 snprintf(exited, sizeof exited, " exec=failed");
375 }
376 else {
377 if( WIFSIGNALED(status) ) {
378 snprintf(trapped, sizeof trapped, " signal=%s",
379 strsignal(WTERMSIG(status)));
380 }
381
382 if( WCOREDUMP(status) )
383 dumped = " core=dumped";
384
385 if( WIFEXITED(status) ) {
386 result = WEXITSTATUS(status);
387 snprintf(exited, sizeof exited, " exit_code=%d", result);
388 }
389 }
390
391 if( result != 0 ) {
392 log_warning("EXEC %s; from %s:%d: %s();%s%s%s result=%d",
393 command, file, line, func,
394 exited, trapped, dumped, result);
395 }
396
397 return result;
398}
399
402FILE *
403common_popen_(const char *file, int line, const char *func,
404 const char *command, const char *type)
405{
406 LOG_REGISTER_CONTEXT;
407
408 log_debug("EXEC %s; from %s:%d: %s()",
409 command, file, line, func);
410
411 return popen(command, type);
412}
413
414waitres_t
415common_wait(unsigned tot_ms, bool (*ready_cb)(void *aptr), void *aptr)
416{
417 LOG_REGISTER_CONTEXT;
418
419 struct timespec ts;
420
421 waitres_t res = WAIT_FAILED;
422
423 for( ;; ) {
424 unsigned nap_ms = (tot_ms > 200) ? 200 : tot_ms;
425
426 ts.tv_sec = (nap_ms / 1000);
427 ts.tv_nsec = (nap_ms % 1000);
428 ts.tv_nsec *= 1000 * 1000;
429
430 for( ;; ) {
431 if( ready_cb && ready_cb(aptr) ) {
432 res = WAIT_READY;
433 goto EXIT;
434 }
435
436 if( tot_ms <= 0 ) {
437 res = WAIT_TIMEOUT;
438 goto EXIT;
439 }
440
441 if( worker_bailing_out() ) {
442 log_warning("wait canceled");
443 goto EXIT;
444 }
445
446 if( nanosleep(&ts, &ts) == 0 )
447 break;
448
449 if( errno != EINTR ) {
450 log_warning("wait failed: %m");
451 goto EXIT;
452 }
453 }
454
455 tot_ms -= nap_ms;
456 }
457
458EXIT:
459 return res;
460}
461
464bool
465common_msleep_(const char *file, int line, const char *func, unsigned msec)
466{
467 LOG_REGISTER_CONTEXT;
468
469 log_debug("SLEEP %u.%03u seconds; from %s:%d: %s()",
470 msec / 1000u, msec % 1000u,file, line, func);
471 return common_wait(msec, 0, 0) == WAIT_TIMEOUT;
472}
473
474/* ------------------------------------------------------------------------- *
475 * MISC
476 * ------------------------------------------------------------------------- */
477
478/* check if a mode is in a list */
479static bool common_mode_in_list(const char *mode, char * const *modes)
480{
481 LOG_REGISTER_CONTEXT;
482
483 int i;
484
485 if (!modes)
486 return false;
487
488 for(i = 0; modes[i] != NULL; i++)
489 {
490 if(!strcmp(modes[i], mode))
491 return true;
492 }
493 return false;
494}
495
502bool
503common_modename_is_internal(const char *modename)
504{
505 LOG_REGISTER_CONTEXT;
506
507 return (common_modename_is_static(modename) ||
508 !g_strcmp0(modename, MODE_ASK) ||
509 !g_strcmp0(modename, MODE_BUSY));
510}
511
518bool
519common_modename_is_static(const char *modename)
520{
521 LOG_REGISTER_CONTEXT;
522
523 return (!g_strcmp0(modename, MODE_UNDEFINED) ||
524 !g_strcmp0(modename, MODE_CHARGER) ||
525 !g_strcmp0(modename, MODE_CHARGING_FALLBACK) ||
526 !g_strcmp0(modename, MODE_CHARGING));
527}
528
535int common_valid_mode(const char *mode)
536{
537 LOG_REGISTER_CONTEXT;
538
539 int valid = 1;
540 /* MODE_ASK, MODE_CHARGER and MODE_CHARGING_FALLBACK are not modes that are settable seen their special 'internal' status
541 * so we only check the modes that are announed outside. Only exception is the built in MODE_CHARGING */
542 if(!strcmp(MODE_CHARGING, mode)) {
543 valid = 0;
544 }
545 else
546 {
547 const modedata_t *data = usbmoded_get_modedata(mode);
548
549 if( data ) {
550 gchar *whitelist_value = 0;
551 gchar **whitelist_array = 0;
552
553 if( (whitelist_value = config_get_mode_whitelist()) )
554 whitelist_array = g_strsplit(whitelist_value, ",", 0);
555
556 if (!whitelist_array || common_mode_in_list(data->mode_name, whitelist_array))
557 valid = 0;
558
559 g_strfreev(whitelist_array);
560 g_free(whitelist_value);
561 }
562 }
563 return valid;
564}
565
575{
576 LOG_REGISTER_CONTEXT;
577
578 GString *mode_list_str = g_string_new(NULL);
579
580 gchar *hidden_modes_value = 0;
581 gchar **hidden_modes_array = 0;
582
583 gchar *whitelist_value = 0;
584 gchar **whitelist_array = 0;
585
586 if( usbmoded_get_diag_mode() )
587 {
588 /* diag mode. there is only one active mode */
589 g_string_append(mode_list_str, MODE_DIAG);
590 goto EXIT;
591 }
592
593 if( (hidden_modes_value = config_get_hidden_modes()) )
594 hidden_modes_array = g_strsplit(hidden_modes_value, ",", 0);
595
596 switch( type ) {
598 /* All modes that are not hidden */
599 break;
600
602 /* All whitelisted modes that are not hidden */
603 if( (whitelist_value = config_get_mode_whitelist()) )
604 whitelist_array = g_strsplit(whitelist_value, ",", 0);
605 break;
606 }
607
608 for( GList *iter = usbmoded_get_modelist(); iter; iter = g_list_next(iter) )
609 {
610 modedata_t *data = iter->data;
611
612 /* skip dynamic modes that are not allowed */
613 if (!usbmoded_is_mode_permitted(data->mode_name, uid))
614 continue;
615
616 /* skip items in the hidden list */
617 if (common_mode_in_list(data->mode_name, hidden_modes_array))
618 continue;
619
620 /* if there is a whitelist skip items not in the list */
621 if (whitelist_array && !common_mode_in_list(data->mode_name, whitelist_array))
622 continue;
623
624 g_string_append(mode_list_str, data->mode_name);
625 g_string_append(mode_list_str, ", ");
626 }
627
628 /* End with charging mode */
629 g_string_append(mode_list_str, MODE_CHARGING);
630
631EXIT:
632 g_strfreev(whitelist_array);
633 g_free(whitelist_value);
634
635 g_strfreev(hidden_modes_array);
636 g_free(hidden_modes_value);
637
638 return g_string_free(mode_list_str, false);
639}
const char * internal_mode
const char * hardware_mode
const char * external_mode
void common_release_wakelock(const char *wakelock_name)
int common_valid_mode(const char *mode)
int common_system_(const char *file, int line, const char *func, const char *command)
void common_send_available_modes_signal(void)
FILE * common_popen_(const char *file, int line, const char *func, const char *command, const char *type)
void common_send_whitelisted_modes_signal(void)
void common_send_hidden_modes_signal(void)
gchar * common_get_mode_list(mode_list_type_t type, uid_t uid)
bool common_modename_is_internal(const char *modename)
void common_acquire_wakelock(const char *wakelock_name)
bool common_msleep_(const char *file, int line, const char *func, unsigned msec)
bool common_modename_is_static(const char *modename)
void common_send_supported_modes_signal(void)
mode_list_type_t
@ AVAILABLE_MODES_LIST
@ SUPPORTED_MODES_LIST
int umdbus_send_hidden_modes_signal(const char *hidden_modes)
int umdbus_send_available_modes_signal(const char *available_modes)
int umdbus_send_supported_modes_signal(const char *supported_modes)
int umdbus_send_whitelisted_modes_signal(const char *whitelist)
#define MODE_ASK
#define MODE_CHARGING
#define MODE_CHARGING_FALLBACK
#define MODE_UNDEFINED
#define MODE_CHARGER
#define MODE_BUSY
const modedata_t * usbmoded_get_modedata(const char *modename)
Definition usb_moded.c:252
GList * usbmoded_get_modelist(void)
Definition usb_moded.c:197
#define USB_MODED_SUSPEND_DELAY_MAXIMUM_MS
Definition usb_moded.h:56