mod bz5 - fix hw that comes with bt rfkill on and bz adapters empty

so - it seems on some hardware and./or os combinations the list of bt
adapters is empty from bluez5 entirely if the adapter is rfkilled off.
this means e doesnt see it at all - has no idea it's there. bz doesnt
expose it. without that we can't turn it on even. so - if our bt
adapter list is empty, then assume this is an error and manually list
rfkillable devines and forcibly unblock them ot make them appear in
bulez5... not so much a bug fix as a system brokenness workaround with
bz5 just ignoring rfkill bnlocked devices and not even telling us
about them.

@fix
This commit is contained in:
Carsten Haitzler 2021-04-06 19:25:28 +01:00
parent 128459b6bf
commit f9607a9084
2 changed files with 138 additions and 28 deletions

View File

@ -1,12 +1,20 @@
#include "e_system.h" #include "e_system.h"
typedef enum
{
RFKILL_BLOCK,
RFKILL_UNBLOCK,
RFKILL_LIST,
} RFKill_Action;
typedef struct typedef struct
{ {
char *dev; char *dev;
Ecore_Event_Handler *handle_del, *handle_data; Ecore_Event_Handler *handle_del, *handle_data;
Ecore_Exe *exe; Ecore_Exe *exe;
int id; int id;
Eina_Bool block : 1; RFKill_Action act;
Eina_Strbuf *list_ret;
Eina_Bool doit : 1; Eina_Bool doit : 1;
} Action; } Action;
@ -21,7 +29,8 @@ _rfkill_dev_verify(const char *dev)
((*s >= 'A') && (*s <= 'Z')) || ((*s >= 'A') && (*s <= 'Z')) ||
((*s >= '0') && (*s <= '9')) || ((*s >= '0') && (*s <= '9')) ||
(*s == '-') || (*s == '+') || (*s == ',') || (*s == '.') || (*s == '-') || (*s == '+') || (*s == ',') || (*s == '.') ||
(*s == '/') || (*s == ':') || (*s == '=') || (*s == '@'))) (*s == '/') || (*s == ':') || (*s == '=') || (*s == '@') ||
(*s == '_')))
return EINA_FALSE; return EINA_FALSE;
} }
return EINA_TRUE; return EINA_TRUE;
@ -34,6 +43,7 @@ _rfkill_action_free(Action *a)
// if (a->exe) ecore_exe_free(a->exe); // if (a->exe) ecore_exe_free(a->exe);
if (a->handle_del) ecore_event_handler_del(a->handle_del); if (a->handle_del) ecore_event_handler_del(a->handle_del);
if (a->handle_data) ecore_event_handler_del(a->handle_data); if (a->handle_data) ecore_event_handler_del(a->handle_data);
if (a->list_ret) eina_strbuf_free(a->list_ret);
free(a->dev); free(a->dev);
free(a); free(a);
} }
@ -48,10 +58,10 @@ _cb_rfkill_exe_del(void *data, int ev_type EINA_UNUSED, void *event)
{ {
if (a->doit) if (a->doit)
{ {
if (a->block) if (a->act == RFKILL_BLOCK)
e_system_inout_command_send("rfkill-block", "%i %s", e_system_inout_command_send("rfkill-block", "%i %s",
ev->exit_code, a->dev); ev->exit_code, a->dev);
else else if (a->act == RFKILL_UNBLOCK)
e_system_inout_command_send("rfkill-unblock", "%i %s", e_system_inout_command_send("rfkill-unblock", "%i %s",
ev->exit_code, a->dev); ev->exit_code, a->dev);
_rfkill_action_free(a); _rfkill_action_free(a);
@ -63,31 +73,52 @@ _cb_rfkill_exe_del(void *data, int ev_type EINA_UNUSED, void *event)
// a->exe can stay - exe's are auto-freed by ecore on exit // a->exe can stay - exe's are auto-freed by ecore on exit
// ecore_exe_free(a->exe); // ecore_exe_free(a->exe);
a->exe = NULL; a->exe = NULL;
if (snprintf(cmd, sizeof(cmd), "rfkill %s %i", if ((a->act == RFKILL_BLOCK) || (a->act == RFKILL_UNBLOCK))
a->block ? "block" : "unblock", a->id) <
(int)(sizeof(cmd) - 1))
{ {
a->doit = EINA_TRUE; if (snprintf(cmd, sizeof(cmd), "rfkill %s %i",
a->exe = ecore_exe_pipe_run(cmd, (a->act == RFKILL_BLOCK) ? "block" : "unblock",
ECORE_EXE_NOT_LEADER | a->id) < (int)(sizeof(cmd) - 1))
ECORE_EXE_TERM_WITH_PARENT | {
ECORE_EXE_PIPE_READ | a->doit = EINA_TRUE;
ECORE_EXE_PIPE_WRITE | a->exe = ecore_exe_pipe_run(cmd,
ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL); ECORE_EXE_NOT_LEADER |
if (!a->exe) _rfkill_action_free(a); ECORE_EXE_TERM_WITH_PARENT |
ECORE_EXE_PIPE_READ |
ECORE_EXE_PIPE_WRITE |
ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL);
if (!a->exe) _rfkill_action_free(a);
}
}
else if (a->act == RFKILL_LIST)
{
e_system_inout_command_send("rfkill-list", "-");
_rfkill_action_free(a);
} }
else _rfkill_action_free(a); else _rfkill_action_free(a);
} }
} }
else else
{ {
if (a->block) if (a->act == RFKILL_BLOCK)
e_system_inout_command_send("rfkill-block", "%i %s", e_system_inout_command_send("rfkill-block", "%i %s",
123, a->dev); 123, a->dev);
else else if (a->act == RFKILL_UNBLOCK)
e_system_inout_command_send("rfkill-unblock", "%i %s", e_system_inout_command_send("rfkill-unblock", "%i %s",
123, a->dev); 123, a->dev);
_rfkill_action_free(a); else if (a->act == RFKILL_LIST)
{
if (a->list_ret)
{
const char *s = eina_strbuf_string_get(a->list_ret);
if (s)
e_system_inout_command_send("rfkill-list", "%s", s);
else
e_system_inout_command_send("rfkill-list", "-");
}
else
e_system_inout_command_send("rfkill-list", "-");
_rfkill_action_free(a);
}
} }
return EINA_TRUE; return EINA_TRUE;
} }
@ -104,16 +135,26 @@ _cb_rfkill_exe_data(void *data, int ev_type EINA_UNUSED, void *event)
for (i = 0; ev->lines[i].line; i++) for (i = 0; ev->lines[i].line; i++)
{ {
int id; int id;
char dev[1024]; char dev[1024], type[1024];
id = -1; id = -1;
if (sscanf(ev->lines[i].line, "%i: %1023[^:] %*s", &id, dev) == 2) if (sscanf(ev->lines[i].line, "%i: %1023[^:]: %1023[^\n]", &id, dev, type) == 3)
{ {
if (!strcmp(a->dev, dev)) if ((a->act == RFKILL_BLOCK) || (a->act == RFKILL_UNBLOCK))
{ {
a->id = id; if (!strcmp(a->dev, dev))
// wait for exit to spawn rfkill again... {
break; a->id = id;
// wait for exit to spawn rfkill again...
break;
}
}
else
{
if (!a->list_ret) a->list_ret = eina_strbuf_new();
if (a->list_ret)
eina_strbuf_append_printf(a->list_ret, "%s\t%s\n",
dev, type);
} }
} }
} }
@ -121,14 +162,14 @@ _cb_rfkill_exe_data(void *data, int ev_type EINA_UNUSED, void *event)
} }
static void static void
_rfkill_do(Eina_Bool block, const char *dev) _rfkill_do(RFKill_Action act, const char *dev)
{ {
Action *a = calloc(1, sizeof(Action)); Action *a = calloc(1, sizeof(Action));
if (!a) return; if (!a) return;
a->dev = strdup(dev); a->dev = strdup(dev);
if (!a->dev) goto err; if (!a->dev) goto err;
a->id = -1; a->id = -1;
a->block = block; a->act = act;
a->handle_del = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, a->handle_del = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
_cb_rfkill_exe_del, a); _cb_rfkill_exe_del, a);
a->handle_data = ecore_event_handler_add(ECORE_EXE_EVENT_DATA, a->handle_data = ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
@ -152,14 +193,20 @@ static void
_cb_rfkill_block(void *data EINA_UNUSED, const char *params) _cb_rfkill_block(void *data EINA_UNUSED, const char *params)
{ {
if (!_rfkill_dev_verify(params)) return; if (!_rfkill_dev_verify(params)) return;
_rfkill_do(EINA_TRUE, params); _rfkill_do(RFKILL_BLOCK, params);
} }
static void static void
_cb_rfkill_unblock(void *data EINA_UNUSED, const char *params) _cb_rfkill_unblock(void *data EINA_UNUSED, const char *params)
{ {
if (!_rfkill_dev_verify(params)) return; if (!_rfkill_dev_verify(params)) return;
_rfkill_do(EINA_FALSE, params); _rfkill_do(RFKILL_UNBLOCK, params);
}
static void
_cb_rfkill_list(void *data EINA_UNUSED, const char *params EINA_UNUSED)
{
_rfkill_do(RFKILL_LIST, "");
} }
void void
@ -167,6 +214,7 @@ e_system_rfkill_init(void)
{ {
e_system_inout_command_register("rfkill-block", _cb_rfkill_block, NULL); e_system_inout_command_register("rfkill-block", _cb_rfkill_block, NULL);
e_system_inout_command_register("rfkill-unblock", _cb_rfkill_unblock, NULL); e_system_inout_command_register("rfkill-unblock", _cb_rfkill_unblock, NULL);
e_system_inout_command_register("rfkill-list", _cb_rfkill_list, NULL);
} }
void void

View File

@ -9,6 +9,8 @@ static E_Config_DD *conf_device_edd = NULL;
static E_Config_DD *conf_edd = NULL; static E_Config_DD *conf_edd = NULL;
Config *ebluez5_config = NULL; Config *ebluez5_config = NULL;
static Ecore_Timer *zero_adapters_check_timer = NULL;
E_API E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Bluez5"}; E_API E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Bluez5"};
static void static void
@ -210,6 +212,48 @@ _cb_rfkill_unblock(void *datam EINA_UNUSED, const char *params)
"users and groups there to be sure.")); "users and groups there to be sure."));
} }
static void
_cb_rfkill_list(void *datam EINA_UNUSED, const char *params)
{
if ((!params) || (!strcmp(params, "-"))) return;
// params is:
// hci0\tBluetooth\n
// phy0\tWireless LAN\n
// ...
// we got a list of possible rf-killable devices and this list callback
// will only have happened if we requested a list which we only do if
// tjhe list of adapters is empty still 5 seconds after init - something
// possibly wrong with them being blocked and thbus bluez not even listing
// them, so unblock them to get them listed
char **lines = eina_str_split(params, "\n", 0);
if (lines)
{
int i = 0;
char *line = lines[i];
while (line)
{
char **fields = eina_str_split(line, "\t", 0);
if (fields)
{
if ((fields[0]) && (fields[1]))
{
if (!strcasecmp(fields[1], "bluetooth"))
{
ebluez5_rfkill_unblock(fields[0]);
}
}
free(fields[0]);
free(fields);
}
i++;
line = lines[i];
}
free(lines[0]);
free(lines);
}
}
void void
ebluez5_rfkill_unblock(const char *name) ebluez5_rfkill_unblock(const char *name)
{ {
@ -329,6 +373,15 @@ ebluez5_device_prop_unlock_set(const char *address, Eina_Bool enable)
} }
} }
static Eina_Bool
_cb_zero_adapters_check(void *data EINA_UNUSED)
{
zero_adapters_check_timer = NULL;
if (!ebluez5_popup_adapters_get())
e_system_send("rfkill-list", "-");
return EINA_FALSE;
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/* Module Functions */ /* Module Functions */
@ -364,6 +417,7 @@ e_modapi_init(E_Module *m)
E_CONFIG_LIST(D, T, devices, conf_device_edd); E_CONFIG_LIST(D, T, devices, conf_device_edd);
e_system_handler_add("rfkill-unblock", _cb_rfkill_unblock, NULL); e_system_handler_add("rfkill-unblock", _cb_rfkill_unblock, NULL);
e_system_handler_add("rfkill-list", _cb_rfkill_list, NULL);
ebluez5_config = e_config_domain_load("module.ebluez5", conf_edd); ebluez5_config = e_config_domain_load("module.ebluez5", conf_edd);
if (!ebluez5_config) ebluez5_config = E_NEW(Config, 1); if (!ebluez5_config) ebluez5_config = E_NEW(Config, 1);
@ -373,6 +427,8 @@ e_modapi_init(E_Module *m)
e_gadcon_provider_register(&_gc_class); e_gadcon_provider_register(&_gc_class);
zero_adapters_check_timer = ecore_timer_add(5.0, _cb_zero_adapters_check, NULL);
return m; return m;
} }
@ -382,6 +438,12 @@ e_modapi_shutdown(E_Module *m EINA_UNUSED)
Config_Adapter *ad; Config_Adapter *ad;
Config_Device *dev; Config_Device *dev;
if (zero_adapters_check_timer)
{
ecore_timer_del(zero_adapters_check_timer);
zero_adapters_check_timer = NULL;
}
e_system_handler_del("rfkill-list", _cb_rfkill_list, NULL);
e_system_handler_del("rfkill-unblock", _cb_rfkill_unblock, NULL); e_system_handler_del("rfkill-unblock", _cb_rfkill_unblock, NULL);
EINA_LIST_FREE(ebluez5_config->adapters, ad) EINA_LIST_FREE(ebluez5_config->adapters, ad)
{ {