Starten eines Skripts als ein anderer Benutzer

12

Ich habe ein Skript in /etc/init.d/ erstellt, das mehrere andere Skripte von anderen (nicht root-privilegierten) Benutzern aus ihren Home-Verzeichnissen ausführen muss, als ob sie sie gestartet hätten.

Ich starte diese Skripte mit: sudo -b -u <username> <script_of_a_particular_user>

Und es funktioniert. Aber für jedes Benutzerskript, das weiterhin ausgeführt wird (zum Beispiel einen Watchdog), wird ein entsprechender übergeordneter sudo-Prozess angezeigt, der noch aktiv ist und als root ausgeführt wird. Dies erzeugt ein Durcheinander in der Liste der aktiven Prozesse.

Meine Frage lautet also: Wie kann ich ein anderes Skript aus einem vorhandenen Bash-Skript als ein anderer Benutzer starten (forken) und es als verwaisten (eigenständigen) Prozess belassen?

Detailliertere Erklärung:
Ich versuche im Grunde, anderen Benutzern auf dem Computer eine Möglichkeit zu bieten, Dinge beim Systemstart oder Herunterfahren auszuführen, indem ausführbare Dateien ausgeführt werden, die in den jeweiligen Unterverzeichnissen in ihrem Ausgangsverzeichnis mit den Namen .startUp und .shutDown gespeichert sind. Da ich keine andere Möglichkeit gefunden habe, dies zu tun, habe ich mein Bash-Skript geschrieben, das genau das tut, und ich habe es als Dienstskript konfiguriert (indem ich dem Beispiel im Grundgerüst folge), und zwar in /etc/init.d/, wenn es ausgeführt wird Mit dem Start-Argument wird alles aus den .startUp-Verzeichnissen gestartet, und wenn es mit dem Stop-Argument ausgeführt wird, wird alles aus den .shutDown-Verzeichnissen aller Benutzer als solche gestartet.

Alternativ bin ich auch interessiert, ob ich eine vorhandene Lösung hätte verwenden können, um dieses Problem zu lösen.

UPDATE
Ich habe mich ein bisschen umgesehen und diese Frage gefunden: /unix/22478/detach-a-daemon-using-sudo

Akzeptierte Antwort dort, zu verwenden:, sudo -u user sh -c "daemon & disown %1"funktioniert bei mir so. Aber ich habe es auch ohne % 1 versucht und es ist dasselbe. Das funktioniert bei mir also so, wie ich es erwartet hatte:

sudo -u <username> bash -c "<script_of_a_particular_user> &"

Meine zusätzliche Frage ist nun, warum es funktioniert, ohne es zu verleugnen. soll ich die verläßt noch disown Anruf, egal, für einigen möglichen Sonderfall?

UPDATE 2

Anscheinend funktioniert das auch:

su <username> -c "<script_of_a_particular_user> &"

Gibt es einen Unterschied zwischen diesem Aufruf und dem Sudo-Aufruf? Ich weiß, dass dies möglicherweise eine ganz andere Frage ist. Aber da ich hier selbst die Antworten finde, könnte dies hier jemand klären.

UPDATE 3
Diese beiden Methoden mit su oder sudo erzeugen jetzt einen neuen startpar- Prozess (einzelner Prozess, der als root ausgeführt wird), nachdem ich den Computer gestartet habe. In der Prozessliste sichtbar als:

startpar -f -- <name_of_my_init.d_script>

Warum wird dieser Prozess ausgelöst? Offensichtlich mache ich etwas falsch, da kein anderes init.d-Skript diesen Prozess ausführt.

UPDATE 4
Das Problem mit startpar wurde behoben. Ich habe eine andere Frage dazu gestartet:
startpar process blieb hängen, wenn Prozesse von rc.local oder init.d gestartet wurden

Und noch eine Frage, um die Startmechanismen für nicht privilegierte Benutzer weiter zu diskutieren: Bereitstellung von Funktionen zum automatischen Starten und Herunterfahren für
normale Benutzer (ohne Rootberechtigung)

Ivan Kovacevic
quelle

Antworten:

18

Die richtige Antwort dafür war, dass für eine ordnungsgemäße "Dämonisierung" die Standardeingabe, die Standardausgabe und der Standardfehler nach / dev / null (oder in eine echte Datei) umgeleitet werden müssen:

su someuser -c "nohup some_script.sh >/dev/null 2>&1 &"

su - Ersetzen Sie die Benutzeridentität durch das Argument someuser
-c - su, um den angegebenen Befehl auszuführen.
nohup - Führen Sie einen Befehl aus, der gegen Aufhängen immun ist. Um zu verhindern, dass der übergeordnete Prozess den untergeordneten Prozess beendet. Hier für alle Fälle hinzugefügt. Hat aber in meinem speziellen Fall eigentlich keine Auswirkung. Ob es benötigt wird, hängt von der Umgebung ab (check shopt )
> / dev / null - Leitet die Standardausgabe auf nichts um und deaktiviert sie grundsätzlich.
2> & 1 - Leitet die Ausgabe von Standardfehler (2) auf die Standardausgabe (1) um, die auf Null umgeleitet wird.
& - Trennen Sie die Verbindung zum Hintergrund, um die Standardeingabe auch auf / dev / null umzuleiten.

Dies ist im Wesentlichen genau das, was das Dienstprogramm start-stop-daemon von Debian dpkg im Kern macht. Deshalb starte ich Skripte lieber auf diese Weise, als einen weiteren externen Dienstprogrammaufruf in meinen Code einzufügen. start-stop-daemon ist nützlich, wenn Sie über vollständige Daemon-Programme verfügen, die Sie starten müssen, und wenn Sie zusätzliche Funktionen benötigen, die start-stop-daemon bereitstellt (z. B. um zu überprüfen, ob der angegebene Prozess bereits ausgeführt wird, sodass dies nicht der Fall ist) nicht erneut starten).

Es ist auch erwähnenswert, dass Sie auch Dateideskriptoren Ihres Prozesses schließen können, anstatt sie nach / dev / null umzuleiten , zum Beispiel:

su someuser -c "some_script.sh 0<&- 1>&- 2>&- &"

0 <& - Standardeingabe schließen (0)
1> & - Standardausgabe schließen (1)
2> & - Standardfehlerausgabe schließen (2)

Die Richtung der <> -Zeichen spielt keine Rolle, solange die Nummer des Dateideskriptors angegeben ist. Das ist also genauso gut:

su someuser -c "some_script.sh 0>&- 1>&- 2>&- &"

oder

su someuser -c "some_script.sh 0<&- 1<&- 2<&- &"

Es gibt jedoch einen etwas kürzeren Weg, ohne Zahlen für stdin und stdout zu schreiben, wo die Richtung eine Rolle spielt:

su someuser -c "some_script.sh <&- >&- 2>&- &" 

Wenn die Dateideskriptoren entweder geschlossen oder nach / dev / null umgeleitet werden ( start-stop-daemon führt die Umleitung nach / dev / null durch), kann der Prozess sicher als Daemon im Hintergrund ausgeführt werden. Das ist es also, was benötigt wird, um Probleme ( startpar ) beim Starten von Skripten während des Bootens zu vermeiden .

Ich habe die gesamte Lösung von meiner ersten Idee an implementiert und auf GitHub platziert:
https://github.com/ivankovacevic/userspaceServices

Ivan Kovacevic
quelle
Ivan, ist es besser, su oder su -login zu verwenden? Ich habe den Mann von su gelesen, aber ich kann für diesen speziellen Fall nicht verstehen.
Massimo
1
@ Massimo, entschuldige die Verzögerung in meiner Antwort! Schauen Sie sich diese Frage an: unix.stackexchange.com/questions/318572/… dort gibt es eine bessere Handbuchseite, die dies erklärt. Grundsätzlich besteht der Unterschied darin, das Arbeitsverzeichnis und die Umgebungsvariablen festzulegen. Ich würde für solche Anwendungsfälle sagen, dass es eine vorzuziehende Option sein könnte, -login
Ivan Kovacevic
3

Sie können den start-stop-daemon aus init.d mit der --userOption verwenden.

dmourati
quelle
Ich habe über Start-Stop-Daemon zu Mr. Sharks Antwort einen Kommentar abgegeben und auch meine Antwort und meine Frage (Update 4) aktualisiert
Ivan Kovacevic,
2

Ich habe das noch nicht vollständig getestet, aber ich denke, dass so etwas wie:

/sbin/start-stop-daemon --background --start --exec /home/USER/.startUp --user USER --pidfile=/home/USER/.startUp.pid --make-pidfile

beim Start und dann

/sbin/start-stop-daemon --stop --user USER --pidfile=/home/USER/.startUp.pid

beim Herunterfahren.

Die Handhabung des .shutDown-Skripts könnte von so etwas wie dem Startup-Ding übernommen werden, aber Sie können nicht sicher sein, dass die Skripts bis zum Ende ausgeführt werden, da das Herunterfahren sowieso passieren sollte :-)

Sollte dies der Fall sein, sollten Sie vielleicht eine Eingabeumleitung einbauen, aber dann müssen Sie sich Sorgen machen, dass die Protokolldateien gefüllt werden.

Herr Hai
quelle
2
Im Grunde würde das funktionieren! start-stop-daemon kann Prozesse beim Booten oder auf andere Weise erfolgreich starten. Ich habe es getestet. Und es wird auch dieses Problem mit hängenden Startpar-Prozess los. Allerdings fehlt Ihnen in Ihrem Startaufruf auch ein --chuid USER. Ohne würde es den Prozess als root starten. Die PID-Datei sollte wahrscheinlich auch in / var / run / geschrieben werden, da sie andernfalls eine Root-Datei im Home-Verzeichnis des Benutzers generiert. Für ein generisches Skript scheint das Starten von Start-Stop-Daemon jedoch ein wenig übertrieben zu sein. Überprüfe meine Antwort, wo ich versucht habe, den Grund herauszufinden.
Ivan Kovacevic
1

Hast du es versucht su?

su -c /home/user/.startUp/executable - user

-c weist su an, den Befehl auszuführen, und der letzte Parameter ist der Benutzer, der den Befehl ausführt.

Tero Kilkanen
quelle
Ja, das funktioniert aber mit einigem Anführungszeichen und Et-Zeichen. Und ich finde es sauberer, es so zu schreiben: su <Benutzername> -c "/some/path/script.sh &" Grundsätzlich habe ich sudo verwendet, da es sauberer zu sein schien, aber jetzt scheint dies besser zu sein als mit: sudo - u <Benutzername> bash -c "/some/path/script.sh &". Ich weiß aber nicht, ob es bei diesen beiden Unterschiede gibt
Ivan Kovacevic,