mirror of
https://github.com/kawasaki/pyscrlink.git
synced 2025-07-21 17:41:18 +02:00
bluepy_helper_cap.py: Check bluepy-helper capability at scratch-link run
To run bluepy-scratch-link as a normal user bluepy-helper must have cap_net_admin and cap_net_raw capabilities to connect to BLE devices using bluepy. When it lacks these capabilities, bluepy-scratch-link fails to discover BLE devices without message about the failure reason. To inform users the reason of BLE device detection failure, check capabilities of bluepy-helper when discovery of BLE device is requested. If the capabilities are not set, print error messages and request users to run script to set the capabilities. Implement this features in bluepy_helper_cap.py. In addition, re-implement bash script setcap.sh feature as python and added to bluepy_helper_cap.py to simplify the code set. Signed-off-by: Shin'ichiro Kawasaki <kawasaki@juno.dti.ne.jp>
This commit is contained in:
@@ -76,9 +76,8 @@ Installation
|
||||
|
||||
5. Set bluepy-helper capability
|
||||
```
|
||||
./setcap.sh
|
||||
Set up bluepy-helper capability to allow use by normal users
|
||||
/usr/lib/python3.8/site-packages/bluepy-1.3.0-py3.8.egg/bluepy/bluepy-helper = cap_net_admin,cap_net_raw+eip
|
||||
$ sudo ./bluepy_helper_cap.py
|
||||
Set capacbility 'cap_net_raw,cap_net_admin' to /usr/lib/python3.8/site-packages/bluepy-1.3.0-py3.8.egg/bluepy/bluepy-helper
|
||||
```
|
||||
|
||||
6. If using a micro:bit, install Scratch-link hex on your device.
|
||||
|
65
bluepy_helper_cap.py
Executable file
65
bluepy_helper_cap.py
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import bluepy
|
||||
import subprocess
|
||||
|
||||
import logging
|
||||
logLevel = logging.INFO
|
||||
|
||||
# for logging
|
||||
logger = logging.getLogger(__name__)
|
||||
formatter = logging.Formatter(fmt='%(asctime)s %(message)s')
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logLevel)
|
||||
handler.setFormatter(formatter)
|
||||
logger.setLevel(logLevel)
|
||||
logger.addHandler(handler)
|
||||
logger.propagate = False
|
||||
|
||||
# Check dependent tools
|
||||
DEPENDENT_TOOLS = {
|
||||
"setcap": "libcap2-bin (Ubuntu) or libcap (Arch)",
|
||||
}
|
||||
|
||||
for cmd in DEPENDENT_TOOLS:
|
||||
if not shutil.which(cmd):
|
||||
print(f"'{cmd}' not found. Install package {DEPENDENT_TOOLS[cmd]}.")
|
||||
sys.exit(1)
|
||||
|
||||
def helper_path():
|
||||
path = os.path.abspath(bluepy.__file__)
|
||||
if not path:
|
||||
logger.error("Bluepy module not found")
|
||||
sys.exit(1)
|
||||
if path.find("__init__.py") < 0:
|
||||
logger.error(f"Unexpected bluepy module path: {path}")
|
||||
sys.exit(1)
|
||||
path = path.replace("__init__.py", "bluepy-helper")
|
||||
return path
|
||||
|
||||
def is_set():
|
||||
path = helper_path()
|
||||
p = subprocess.run(["getcap", path], capture_output=True)
|
||||
if p.returncode !=0:
|
||||
logger.error(f"Failed to get capability of {path}")
|
||||
return False
|
||||
out = str(p.stdout)
|
||||
return out.find("cap_net_admin") >= 0 and out.find("cap_net_raw") >= 0
|
||||
|
||||
def setcap():
|
||||
path = helper_path()
|
||||
if is_set():
|
||||
return True
|
||||
p = subprocess.run(["setcap", "cap_net_raw,cap_net_admin+eip", path], \
|
||||
capture_output=True)
|
||||
if p.returncode !=0:
|
||||
logger.error(f"Failed to set capability to {path}")
|
||||
return False
|
||||
print(f"Set capacbility 'cap_net_raw,cap_net_admin' to {path}")
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
setcap()
|
@@ -21,6 +21,7 @@ import bluetooth
|
||||
# for BLESession (e.g. BBC micro:bit)
|
||||
from bluepy.btle import Scanner, UUID, Peripheral, DefaultDelegate
|
||||
from bluepy.btle import BTLEDisconnectError, BTLEManagementError
|
||||
import bluepy_helper_cap
|
||||
|
||||
import threading
|
||||
import time
|
||||
@@ -518,6 +519,11 @@ class BLESession(Session):
|
||||
err_msg = None
|
||||
|
||||
if self.status == self.INITIAL and method == 'discover':
|
||||
if not bluepy_helper_cap.is_set():
|
||||
logger.error("Capability is not set to bluepy helper.")
|
||||
logger.error("Run bluepy_setcap.py with root privilege.")
|
||||
logger.error("e.g. $ sudo bluepy_helper_cap.py")
|
||||
sys.exit(1)
|
||||
found_ifaces = 0
|
||||
for i in range(self.MAX_SCANNER_IF):
|
||||
scanner = Scanner(iface=i)
|
||||
|
Reference in New Issue
Block a user