Bash: Wie kann ich "sudo-n true" im Hintergrund ausführen, ohne "read" zu stören?

7

Ich habe ein lang laufendes Bash-Skript, das ich nicht als Root ausführen möchte, das jedoch regelmäßig Root-Zugriff benötigt. Ich habe dieses Problem gelöst, indem ich den Benutzer nach dem Root-Passwort gefragt habe

sudo -v

und dann habe ich einen Prozess hinterlegt, der den Sudo-Timer mit schleifen und zurücksetzen würde

sudo -n true

Ich bekam dann seltsame Probleme bei der Verwendung readim Hauptprozess. Hier ist ein minimales Skript, das dieses Problem zeigt. Wenn Sie es ausführen und vor dem sudo -n trueAusführen nichts eingeben, erhält der Lesevorgang einread error: 0: Resource temporarily unavailable

#!/usr/bin/env bash

sudo -v  # ask user for password

sleep 1 && sudo -n true &  # background a process to reset sudo

printf "Reading text: "
read -n 1 TEXT
echo "Read text: $TEXT"

Ich konnte dieses Verhalten mit keinem anderen Befehl außer replizieren sudo. Wie kann ich sudo -n trueim Hintergrund laufen, ohne mich einzumischen read?

Bearbeiten:

Ich bekomme dieses Problem nur unter Ubuntu, nicht unter MacOS.

Ross MacArthur
quelle
Funktioniert es besser, wenn Sie es sudo -verneut verwenden sudo -n true?
Stephen Kitt
Nein, es gibt das gleiche Verhalten.
Ross MacArthur
Ich kann dieses Problem unter Arch Linux nicht reproduzieren.
Alexander

Antworten:

10

Ich bekomme das gleiche Verhalten mit:

sleep 1 && true < /dev/tty &
read var

sudowird geöffnet /dev/tty, um die aktuelle Vordergrundprozessgruppe abzufragen, wodurch der read()von readbashs ausgeführte Systemaufruf mit EAGAIN mit dem Linux-Kernel 4.15.0-45-generic und 4.18.0-14-generic von Ubuntu 18.04 zurückgegeben wird, wodurch zumindest das readDienstprogramm zurückgegeben wird mit diesem Fehler.

Dies scheint auf einen Fehler in neueren Versionen der Ubuntu-Varianten des Linux-Kernels zurückzuführen zu sein . Ich kann es weder unter Solaris noch unter FreeBSD oder in einer Linux-Version unter Debian reproduzieren (obwohl ich es reproduzieren kann, wenn ich Debian auf Ubuntus 4.18-Kernel starte).

https://bugs.launchpad.net/ubuntu/+source/linux-signed-hwe/+bug/1815021 scheint eine weitere Manifestation dieses Fehlers zu sein.

Dies wird durch https://lkml.org/lkml/2018/11/1/663 eingeführt, das Ubuntu mindestens auf seine Kernel 4.15 und 4.18 zurückportiert hat. Aber Ubuntu hatte bis vor 2 Stunden keine weitere Änderung zurückportiert, die eine durch diesen Patch eingeführte Regression behebt .

4.18.0-15-generic ist jetzt in den Ubuntu-Repositories gelandet und behebt das Problem. Ich nehme an, der für 4.15 wird in Kürze folgen.

ksh93hat nicht das Problem für denselben Code, den der readintegrierte Code zuerst verwendet select(), um auf die Eingabe zu warten, und select()kehrt nicht zurück, wenn der andere Prozess geöffnet wird /dev/tty.

Hier können Sie also ksh93anstelle bashoder warten auf den festen Kernel oder kehren zu 4.15.0-43 zurück, bis 4.15.0-46 veröffentlicht wird.

Alternativ können Sie zshdie integrierte Unterstützung für das Ändern von UIDs (über die speziellen Variablen EUID / UID / USERNAME) verwenden, sofern Sie das Skript starten, rootdamit Sie es nicht sudoinnerhalb des Skripts ausführen müssen (es ist möglicherweise auch gefährlich, die Lebensdauer von zu verlängern das Sudo-Token länger als vom Benutzer erwartet).

Stéphane Chazelas
quelle
1
Ich kann diesen Testfall nicht reproduzieren (welche Bash-Version ist das?) - aber ich sehe nicht, wie eine andere Prozessöffnung /dev/ttydazu führen kann, dass a readzurückkehrt EAGAIN. Sicherlich nicht wegen einer SIGCHLD mit CLD_STOPPED (selbst verursacht durch eine SIGTTIN)? Gibt es einen bekannten Fehler, der das erklärt?
Mosvy
1
@mosvy, nein, wie bestätigt strace, es ist auf jeden Fall die open()auf /dev/ttyden auslöst , die read()mit EAGAIN zurückzukehren. Auf diesem System kann ich mit jeder Shell oder jedem Dienstprogramm reproduzieren, die / das read()auf dem Endgerät ausgeführt wird.
Stéphane Chazelas
Hmm, die einzige Möglichkeit, einen blockierenden EAGAINLesevorgang durchzuführen, besteht darin, O_NONBLOCK für dasselbe Dateiobjekt festzulegen. Beim Öffnen /dev/ttywird jedoch nicht dasselbe Dateiobjekt wie z. /dev/pts/4. zB sleep 1 && perl -MFcntl=F_SETFL,F_GETFL,O_NONBLOCK -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) | O_NONBLOCK' & read fooführt dies nicht dazu, dass der Lesevorgang mit EAGAIN fehlschlägt, wenn die Eingabe von Perl /dev/ttystattdessen umgeleitet wird.
Mosvy
1
@mosvy, beachte, dass ich diesen Fehler mit bash -c 'sleep 1 && true < /dev/tty & read var'4.18 unter Ubuntu bekomme, aber nicht unter Debian. Es kann auch an den sysctl-Optionen liegen. Ich werde versuchen einzugrenzen, was es unter Ubuntu verursacht. In jedem Fall soll EAGAIN zwar von nicht blockierenden Beschreibungen offener Dateien zurückgegeben werden, dies ist hier jedoch nicht der Fall. Es sieht nach einem bestimmten Verhalten des pty-Treibers mit diesen Kerneln aus.
Stéphane Chazelas
1
@mosvy, ich kann das Problem reproduzieren, wenn ich Debian auf dem Ubuntu-Kernel starte. Es sieht aus wie ein Kernel-Bug. bugs.launchpad.net/ubuntu/+source/linux-signed-hwe/+bug/1815021 scheint verwandt zu sein. Ubuntu hat lkml.org/lkml/2018/11/1/663
Stéphane Chazelas