Eu tenho raspberry pi com estoque raspbian instalado. Também instalei o RetroPI, que funciona perfeitamente.
O que eu queria fazer era escrever um pequeno script de inicialização automática que iniciasse o emulationstation (script de execução principal do retropi) quando o game pad estiver conectado via bluetooth. Eu fiz uma regra simples do udev
pi@raspberrypi:~ $ cat /etc/udev/rules.d/99-zlocal.rules
SUBSYSTEM=="bluetooth",SUBSYSTEMS=="amba", ATTRS{id}=="00241011", ACTION=="add", RUN+="/usr/local/bin/emulator-controll.sh start"
que funciona conforme o esperado, o script é executado quando o gamepad é emparelhado.
O problema é que se eu executar meu script via, por exemplo, SSH
sudo emulator-controll.sh start #sudo is optional here, but I want the same conditions as in udev trigger context
estação de emulação conforme esperado.No entanto, se o mesmo script for usado como gatilho de ação para a regra udev acima, ele falharácom erros como
Wed Aug 21 00:02:33 CEST 2019
Invoking user: root
Invoked start command
Invoking emulation station start command
Done
'unknown': I need something more specific.
tput: unknown terminal "unknown"
Segmentation fault
/usr/bin/emulationstation: line 23: /dev/tty: No such device or address
tput: unknown terminal "unknown"
Eu acho que por alguns motivos (sou linux newb) tty não está acessível no contexto do gatilho do udev. Posso consertar isso de alguma forma?
PS. Eu tentei executar o deamon em segundo plano (para usar pipes nomeados) que é iniciado no momento da inicialização, mas o efeito é exatamente o mesmo - não há tty no contexto de execução do script, o que me faz pensar que esse é o comportamento geral das tarefas em segundo plano
O script em si é IMHO irrelevante, mas também o fornecerei para maior clareza:
#!/bin/bash
#/bin/date >> /tmp/udev.log
#env >> /tmp/udev.log
#echo "Connected" > /dev/pts/2
log=/var/log/emulator-controll.log
{
readarray -t PIDS <<< $(ps aux | grep [e]mulationstation | awk '{print $2}')
echo ">${PIDS[@]}<"
echo >> $log
/bin/date >> $log
echo "Invoking user: $(whoami)"
case "$1" in
start )
echo "Invoked start command" >> $log
if [[ "${#PIDS[@]}" -ge 3 ]]; then
echo "Emulator is already running. No action is taken" >> $log
else
echo "Invoking emulation station start command" >> $log
export DISPLAY=:0
sudo -u pi nohup emulationstation &
fi
echo "Done" >> $log
;;
stop )
echo "Invoked stop command" >> $log
if [[ -z "${PIDS[0]}" ]]; then
echo "Emulator is not running, no action is taken" >> $log
else
echo "Killing processes with PIDs ${PIDS[@]}" >> $log
for pid in "${PIDS[@]}"; do
kill $pid
done
echo "Done" >> $log
fi
;;
*)
echo "Usage: $0 {start|stop}"
esac
} >> $log 2>>$log
Responder1
Em vez de tentar anexar o script ao TTY ou atribuir o tty ao script, consegui atingir meu objetivo injetando o comando diretamente no buffer de entrada do destino tty com isto:
sudo writevt /dev/tty1 "emulationstation $(echo -ne '\r')"
isso digita o comando e pressiona “enter” no terminal principal.
PS. writevt
faz parte console-tools
e está disponível no Raspbian (pelo menos hoje)
Responder2
Quando o kernel aciona ações e udev
executa scripts como parte das regras, o ambiente desses scripts é muito restrito.
Pode haver muitos usuários logados simultaneamente em um único computador Linux, cada usuário com vários tty's, entãoclaroum script executado a partir do kernel não possui um tty: Nenhum usuário iniciou este script, portanto, mesmo que alguém pudesse atribuir um tty a ele, qual dos muitos tty em uso deveria ser? E o mesmo vale para uma conexão X (que também é solicitada com frequência).
Existem mais restrições, como você pode ver em man 7 udev
:
CORRER
Adicione um programa à lista de programas a serem executados em um dispositivo específico. Isso só pode ser usado para tarefas de execução muito curta. A execução de um processo de evento por um longo período de tempo pode bloquear todos os eventos adicionais deste dispositivo ou de um dispositivo dependente. Tarefas de longa duração precisam ser imediatamente separadas do próprio processo de evento. Se a opção RUN{fail_event_on_error} for especificada, e o programa executado retornar diferente de zero, o evento será marcado como falhado para um possível tratamento posterior.
Se eu li seu script corretamente, você deseja iniciar ou parar algo em uma determinada conexão X que estará em execução por muito tempo. Isso só funcionará se você dividir sua tarefa em duas: ter algum tipo de demônio que seja iniciado quando o servidor X correspondente for iniciado (o servidor X precisa ser iniciado para que você possa obter o cookie de autorização) e então informar o demônio em o script de execução do udev que deve fazer certas coisas, como iniciar ou parar um serviço.
Dessa forma, o script de execução do udev pode sair imediatamente.
Se você estiver usando o systemd, você também pode iniciar uma unidade a partir de uma regra do udev (veja, por exemplo,aqui).
Editar
Se você quiser usar tty1
, considere alterar o serviço de login ( getty
) executado tty1
em seu demônio, que você pode acionar a partir do script.
Então, por exemploaquipara obter detalhes sobre uma possível maneira de fazer isso, varie conforme necessário.