시스템 서비스의 /dev/stderr

시스템 서비스의 /dev/stderr

LTE 연결을 시작해야 하는 서비스를 작성 중입니다.

하지만 연결하는 데 사용하는 유틸리티(sakis3g)가 를 쓰고 있는데 /dev/stderr, 이는 systemd에서는 사용할 수 없으며 로그가 가득 차 있습니다.

Cannot create /dev/stderr: No such device or address

이 문제를 해결할 방법이 있나요?

불행하게도 유틸리티 스크립트/바이너리를 변경하는 것은 선택 사항이 아닙니다.

편집: 이 서비스는 다음과 같습니다.

[Unit]
Description=LTE
After=syslog.target network-online.target
Before=openvpn-client@client
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/mav/LTE/
ExecStartPre=/sbin/ip link set wwan0 down
ExecStart=/opt/mav/LTE/sakis3g connect -g --sudo
ExecStop=/opt/mav/LTE/sakis3g disconnect --sudo

[Install]
WantedBy=multi-user.target

그리고 이 상태에서 작동합니다. 그러나 더 자세한 디버그 출력 플래그로 시작하면 sakis3g오류 가 -g발생 stderr합니다.

답변1

stderr이 없으면 오류가 표시되지 않습니다.

여기서 오류는 할 수 없다는 것입니다.열려 있는Linux에서 이 /dev/stderr파일은 fd 2에서 열린 실제 파일에 대한 심볼릭 링크입니다(다른 시스템에서 /dev/stderr를 여는 것은 a를 실행하는 것과 같습니다 dup(2)).

여기서 문제는 fd 2가 소켓(inet TCP, Unix 스트림 또는 기타)에서 열려 있고 open()소켓 파일을 열 수 없다는 것입니다.

실행하는 경우:

sudo lsof -aU +E -d 2

사용 중인 시스템에서 systemd대부분의 서비스에 대한 fd 2는 입니다 systemd-journald.

해결 방법으로 다음과 같이 시작할 수 있습니다.

bash -o pipefail -c '{ /opt/mav/LTE/sakis3g connect -g --sudo 2>&1 >&3 3>&- | cat >&2 3>&-; } 3>&1'

즉, stderr를 cat소켓이 아닌 파이프(to)로 만들고, cat파이프에서 수신된 내용을 원래 stderr(소켓)로 전달하고, pipefail이 옵션을 사용하여 명령의 종료 상태를 유지하는지 확인하십시오.

어쨌든 소스는 sakis3g공개되어 있고sakis3g초기화 파일정확히 다음을 수행하는 bash 스크립트입니다.

echo text >> /dev/stderr

바꾸다:

echo test >&2

> /dev/stderr심지어 더 잘못된 것들도 있습니다 >> /dev/stderr. tee -a /dev/stderr | other cmd법적 용도가 없으며 /dev/stderr소켓의 stderr과 작동하지 않으므로 수정하기 쉽습니다.

다음 주소로 문제를 제기하여 문제에 대해 알릴 수 있습니다.https://github.com/Trixarian/sakis3g-source/issues

답변2

tee서비스 내에서 stdout을 수행하는 동안 비슷한 문제가 발생했습니다. 이것은 OP의 정확한 질문은 아니지만또 다른 답변은 "공정 사용 /dev/stderr"이라고 해서 나중에 누군가 필요할 경우를 대비해 여기에 게시할 가치가 있다고 생각했습니다.

즉, 나는 다음을 가지고 있습니다 :

command1 | tee /proc/$$/fd/1 | command2

이 경우 /proc/$$/fd/1항상 shell 이므로 /dev/stdout일반적으로 파이프라인에서 작동합니다. 소켓 열기를 거부했지만 여전히 동일한 문제가 있습니다.

내가 생각해낸 해결책은 tee프로세스 대체를 통해 교체하는 것이었습니다.

command1 | tee >(command2)

이는 아직 완전히 실현되지 않았습니다., 이제 Bash는 종료를 기다리지 않기 때문입니다 command2. 이 문제를 해결하기 위해 다음 방법을 사용할 수 있습니다.이 다른 답변:

{ { command1 | tee >(command2); } 3>&1 >&4 4>&- | cat; } 4>&1

관련 정보