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