Cómo escribir a stdin de un servicio

Sep 30 2020

Tengo un servicio en ejecución que tiene una CLI conectada a stdin. Cuando entro sshen la máquina, me gustaría poder enviar comandos al stdin de ese servicio.

systemd.exec dice que eso StandardInput=file:/path/to/filees una cosa y es compatible con FIFO. Suena como el método más simple.

He probado esto en mi ~/.config/systemd/user/foo.service

[Service]
ExecStartPre=mkfifo %t/foo.stdin
ExecStart=cat -
StandardInput=file:%t/foo.stdin
ExecStopPost=rm -f %t/foo.stdin

En este ejemplo, espero que cuando ejecute lo siguiente, veré el resultado en el diario.

echo "hello" > /run/user/1000/foo.stdin

Tengo dos problemas con esto:

  1. foo.service: Failed to set up standard input: No such file or directory . Parece que StandardInput=debe existir antes ExecStartPre=. ¿Necesitaré crear una tubería permanente en una ubicación estática durante la instalación o hay una solución alternativa? Si hago el archivo manualmente y elimino ExecStartPre/ ExecStopPost, entonces todo funciona.
  2. El primero echo "command"se procesa bien, pero envía un EOFy stdin se cierra. Quería que el stdin permaneciera abierto. La respuesta ( exec 3> stdin, ..., exec 3>&-) parece ser usar la redirección bash FD, pero eso no está disponible en systemd.

Respuestas

3 user3840170 Sep 30 2020 at 09:51

Puede crear una unidad de enchufe para su FIFO:

  • foo.socket:

    [Socket]
    ListenFIFO=%t/foo.stdin
    Service=foo.service
    
  • foo.service:

    [Service]
    ExecStart=/bin/cat -
    Sockets=foo.socket
    StandardInput=socket
    StandardOutput=journal
    StandardError=journal
    

Inícielo de la siguiente manera:

systemctl --user start foo.socket

El servicio en sí se iniciará tan pronto como se escriba el FIFO. Si desea que se inicie de inmediato, ejecútelo así:

systemctl --user start foo.service