無法從以 systemd 啟動的程序訪問 USB 設備
我有以下腳本可以使用 GSM usb 調製解調器發送 SMS 消息:
#!/bin/bash env > /home/hans/systemenv.txt #touch /home/homeassistant/pipo2.txt read count < /home/homeassistant/.homeassistant/smsCounter.txt stty -F /dev/ttyUSB0 9600 min 100 time 2 -hupcl brkint ignpar -opost -onlcr -isig -icanon -echo chat TIMEOUT 1 "" "AT+CMGF=1" "OK" > /dev/ttyUSB0 chat TIMEOUT 1 "" "AT+CMGS=\"0123456789\"" "OK" > /dev/ttyUSB0 chat TIMEOUT 1 "" "$1" "OK" > /dev/ttyUSB0 chat TIMEOUT 1 "" "^Z" "OK" > /dev/ttyUSB0 #sleep 2 #chat TIMEOUT 1 "" "AT+CMGS=\"0987654321\"" "OK" > /dev/ttyUSB0 #chat TIMEOUT 1 "" "$1" "OK" > /dev/ttyUSB0 #chat TIMEOUT 1 "" "^Z" "OK" > /dev/ttyUSB0 let 'count++' echo $count > /home/homeassistant/.homeassistant/smsCounter.txt
從命令行呼叫該腳本時可以正常工作,但是當從使用 systemd 啟動的任何程序呼叫它時,腳本實際上會執行,但聊天命令不會被執行。執行 sudo journalctl -f -xe,當從 systemd 服務中執行的程序呼叫腳本時顯示以下內容:
Oct 08 13:37:37 homeassistant chat[2641]: Can't get terminal parameters: Inappropriate ioctl for device Oct 08 13:37:37 homeassistant chat[2642]: Can't get terminal parameters: Inappropriate ioctl for device Oct 08 13:37:37 homeassistant chat[2643]: Can't get terminal parameters: Inappropriate ioctl for device Oct 08 13:37:37 homeassistant chat[2644]: Can't get terminal parameters: Inappropriate ioctl for device
在這種情況下,腳本是從一個名為 home assistant 的程序中呼叫的。家庭助理是從 systemd.service 腳本啟動的。如果我從終端啟動家庭助手,作為 systemd.service 執行的同一使用者,則上述內容不會顯示並且發送簡訊。
從使用 systemctl 啟動的任何其他程序呼叫相同的腳本會導致相同的錯誤。
這與 systemd 無關,也與程序
systemctl
的基本正確使用無關chat
。
chat
是一個通常與 PPP 守護程序捆綁在一起的程序,至少從 1996 年開始,Al Longyear 維護的Linux PPP FAQ中已經回答了這個問題:17.6。我跑了
chat
。它似乎想將本地終端用作調製解調器並且它不與調製解調器對話。如何指定調製解調器名稱chat
?
chat
屬於一類稱為“過濾器”的程序。也就是說,它從標準輸入讀取,在內部進行一些處理,然後寫入標準輸出。因此,如果您真的只想執行
chat
並讓它與調製解調器通信,那麼您需要使用 I/O 重定向運算符<
,>
以便將標準輸入和輸出重定向到調製解調器。但是,如果您使用
chat
withpppd
,請$$ … $$
看看你在做什麼:
聊天超時 1 "" "AT+CMGF=1" "OK" > /dev/ttyUSB0
您正在執行
chat
它的標準輸出連接到串列設備,但它的標準輸入連接到任何封閉的 shell 腳本的標準輸入。當您從互動式登錄會話執行 shell 腳本時,這將是終端,當您從守護程序執行 shell 腳本時,它將是守護程序的標準輸入,無論是什麼(幾乎肯定不會是終端字元設備)。難怪
chat
不與串口設備聊天。難怪chat
當您從守護程序執行 shell 腳本時,它甚至沒有與終端設備對話。所以
chat
正確使用,正如Linux PPP FAQ所說。將其標準輸入和輸出設置為同一設備,即您嘗試與之通信的設備。
chat
一旦您開始使用chat
連接到正確的設備,您可能不想在所有這些多次呼叫中打開和關閉串列設備。同樣,這與 systemd 或守護程序無關,而是從具有共享標準標準輸入和輸出文件描述的 shell 執行多個連續命令的機制中的簡單練習。或者,實際上,取決於它的作用,甚至以這種方式執行整個 shell 腳本,將整個腳本的標準輸入和輸出重定向到適當的設備,無論程序首先呼叫該腳本。(在這種情況下,使用
-s
選項以chat
獲得最佳結果。)
該問題可能是由 SystemD 程序沒有(控制)終端引起的。
更好的解決方案是使用
chat
正確的 JdeBP 的答案,但對於一般情況……您可以將此程式碼添加到腳本中:
tty &>/dev/null || exec </dev/tty
/dev/tty
這將作為(控制)終端打開。