startup: report PC/SC access denial instead of a silent serial fallback
When no reader was named and readers() failed (e.g. SCARD_E_NO_ACCESS - the user may not use pcscd), the auto-detect swallowed the error and pySim fell back to the Serial transport, failing on /dev/ttyUSB0 while the server still printed "listening". The startup now probes PC/SC, classifies the failure by hresult (access/service/reader), reports the cause with the pcscd group/polkit and pcsc_scan guidance and exits 2; the python -m guard uses sys.exit(main()). An explicit -d/--device keeps the serial path; a reader without a card stays a normal cardless start; a readerless start exits with its own message. start.sh runs the same access pre-flight before launching (readers() with a 3x retry for socket activation; -d is detected and skips it). READMEs, CHANGELOG (folded into the unreleased 3.38.1) and AGENTS updated. Tests: tests/test_pcsc_startup.py (16: the error classifier, the probe, the report guidance, the serial-arg detection and the source pins). 1083 Python + 1075 frontend.
This commit is contained in:
@@ -16,14 +16,50 @@ LOG_FILE="$SCRIPT_DIR/simple_lastrun.log"
|
||||
exec > >(tee "$LOG_FILE") 2>&1
|
||||
export PYTHONUNBUFFERED=1 # keep the log live: a piped stdout is block-buffered
|
||||
|
||||
# Auto-detect reader
|
||||
# PC/SC pre-flight (v3.38.1): a user without access to pcscd must see the real
|
||||
# cause - the server no longer falls back to /dev/ttyUSB0 silently. An
|
||||
# explicit serial reader (-d/--device) keeps the serial path.
|
||||
SERIAL=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
-d|--device|--device=*|-d*) SERIAL=1 ;;
|
||||
esac
|
||||
done
|
||||
READER_ARGS=""
|
||||
if command -v pcscd > /dev/null 2>&1; then
|
||||
# Give pcscd a moment if it's not running yet (USB enumeration delay)
|
||||
if ! pgrep -x pcscd > /dev/null 2>&1 && ! pgrep -x pcscd.bin > /dev/null 2>&1; then
|
||||
sleep 1
|
||||
fi
|
||||
if pgrep -x pcscd > /dev/null 2>&1 || pgrep -x pcscd.bin > /dev/null 2>&1; then
|
||||
if [ "$SERIAL" -eq 0 ]; then
|
||||
PYTHON_BIN="$VENV_DIR/bin/python"
|
||||
[ -x "$PYTHON_BIN" ] || PYTHON_BIN="$(command -v python3 || true)"
|
||||
if [ -n "$PYTHON_BIN" ]; then
|
||||
PCSC_ERR="$("$PYTHON_BIN" - <<'PY' 2>&1
|
||||
import time
|
||||
from smartcard.System import readers
|
||||
last = None
|
||||
for _ in range(3):
|
||||
try:
|
||||
readers()
|
||||
raise SystemExit(0)
|
||||
except SystemExit:
|
||||
raise
|
||||
except Exception as e:
|
||||
last = e
|
||||
hr = getattr(e, 'hresult', None)
|
||||
if hr == 0x80100027 or 'access denied' in str(e).lower():
|
||||
break # permissions do not fix themselves
|
||||
time.sleep(1) # pcscd may still be starting (socket activation)
|
||||
hr = getattr(last, 'hresult', -1)
|
||||
msg = str(last) or 'PC/SC error'
|
||||
print(msg + ((' (hresult=0x%08X)' % hr) if hr not in (None, -1) else ''))
|
||||
raise SystemExit(1)
|
||||
PY
|
||||
)" || {
|
||||
echo "Error: PC/SC is not accessible: ${PCSC_ERR:-unknown error}"
|
||||
echo " The server will not fall back to a serial reader silently."
|
||||
echo " - add the user to the pcscd group: sudo usermod -aG pcscd \"$USER\" (then log out/in),"
|
||||
echo " or configure the polkit rule that allows the user to use pcscd;"
|
||||
echo " - 'sudo systemctl start pcscd' if the service is not running;"
|
||||
echo " - 'pcsc_scan' shows the same 'Access denied' error when access is denied."
|
||||
exit 2
|
||||
}
|
||||
READER_ARGS="-p 0"
|
||||
fi
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user