Single-file Python CLI for a Qualcomm modem's EFS2 filesystem over the DIAG serial port: ls, stat, pull, push, and recursive backup. Talks DIAG over pyserial to work around EfsTools' libnserial EIO on option-driver diag ports. Auto-detects the port by probing for a DIAG response.
3.1 KiB
qcdm-efs2
A small command-line client for a Qualcomm modem's EFS2 filesystem, over the DIAG serial port, in one file of Python. List, stat, pull, push, and back up files in the modem's EFS from Linux, no Windows and no QPST.
I wrote it to back up and replace the RF band policy files (/policyman) on a
rooted Sony Xperia 1 VI, after finding that the usual tool,
EfsTools, fails on Linux against the
option-driver diag port: its native serial layer sets modem control lines on
open and the driver rejects the ioctl with EIO. pyserial opens the same
port fine, so this talks DIAG over pyserial instead. The EFS2 packet layouts
are taken from EfsTools, so the wire format is identical; only the serial
handling differs.
The full write-up, including the Xperia band-unlock use case, is here.
Requirements
- Python 3
pyserial(pip install pyserial)- A rooted phone with a Qualcomm modem, in DIAG mode
- Root on the Linux host to bind the serial driver
Getting the phone onto a serial port
Put the phone into a USB composition that exposes the DIAG port (keeps adb):
adb shell su -c 'setprop sys.usb.config diag,serial_cdev,rmnet,adb'
It re-enumerates as a Qualcomm DIAG device (05c6:9091). The kernel does not
bind a serial driver on its own, so load option and hand it the USB id:
sudo modprobe option
echo 05c6 9091 | sudo tee /sys/bus/usb-serial/drivers/option1/new_id
That composition exposes a few serial nodes and only one is DIAG. You don't
have to work out which: efs2.py probes each candidate, sends a DIAG version
request, and keeps the one that answers. It looks at /dev/serial/by-id/
interface 0 (-if00-) first, then the rest. Set DIAGPORT or pass --port to
override.
Usage
efs2.py [-h] [-p PORT] {ls,stat,pull,push,backup} ...
ls list an EFS directory
stat stat an EFS file
pull download one EFS file
push upload/overwrite one EFS file, then verify the read-back
backup recursively download an EFS directory
Examples:
# see what is in the modem's band-policy folder
python3 efs2.py ls /policyman
# back up a whole directory (subdirectories included) before changing anything
python3 efs2.py backup /policyman ./policyman-backup
# download and upload single files
python3 efs2.py pull /policyman/band_set_01.xml
python3 efs2.py push band_set_01.xml /policyman/band_set_01.xml
push deletes the target, re-creates it, writes in 1 KB chunks, then reads it
back and reports whether it matches. That read-back is the point: a truncated
write to the modem EFS is how you get a modem that won't register.
Warning
This writes to the modem's EFS. A bad write to the wrong file can stop the
modem from booting or registering. Always backup first, and know your
recovery path (for Sony phones, reflashing the modem .sin files with
Newflasher restores stock EFS). Use at your own risk.
License
MIT, see License.txt. EFS2 protocol layouts derived from
EfsTools by JohnBel.