Externes Programm getrennt von Hauptprogramm ausführen?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Stevie
Beiträge: 43
Registriert: Di 27. Feb 2024, 22:40

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Stevie »

Hi ho,
nohub als Beispiel habe ich hier unter Arch – zumindest bei mir – nicht installiert. Ist also keine sichere Option für Linux.
also das Programm heißt nohup und nicht nohub und es ist bei jeder normalen Linux-Distribution im Paket "coreutils" und somit im Basissystem zu finden. Das ist auch bei Arch der Fall (siehe https://archlinux.org/packages/core/x86_64/coreutils/ bzw. https://wiki.archlinux.de/title/Nohup). Es mag bei besonders schmalen Docker-Images eventuell fehlen, dann kann man es aber bei Bedarf bestimmt mit in sein Docker-File holen.

Es gibt aber ein grundsätzliches Problem, das zunehmend relevanter werden wird: Prozesse, die länger leben als das Programm / der Prozess, der sie gestartet hat, stellen ein potentielles Risiko für ein langlaufendes System dar, weil sie gerne für Viren oder Backdoors genutzt werden. Die Wahrscheinlichkeit, dass das "einfach mal so" erlaubt wird und robust und plattformübergreifend funktioniert, wird also zunehmend geringer, selbst, wenn Du jetzt noch eine Lösung findest.

Je nachdem, was Du vorhast, könnte es evtl. eine Möglichkeit sein, über den Installer Deiner Anwendung einen plattformspezifischen Dienst zu installieren (Windows Service, Linux systemd Service, Mac LaunchAgent usw.) und Deine Anwendung mit dem Recht auszustatten (bzw. ausstatten zu lassen), den Dienst zu starten, zu stoppen und ihm über eine REST-API Befehle zuzusenden. DIe meisten Langläufer (z.B. Teams, Webex & Co.) machen es bspw. so und es ist am ehesten etwas, das auch morgen noch funktioniert...

Benutzeravatar
six1
Beiträge: 788
Registriert: Do 1. Jul 2010, 19:01

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von six1 »

Hi,
erstelle ein Script, welches die Ausführung deines Programms erledigt.
Hier nur mal als Beispiel:

Code: Alles auswählen

      {$IFDEF Linux}
      AProcess := TProcess.Create(nil);
      AProcess.CommandLine := BASE_SETTINGS.PFAD_SCRIPT+'restartPC.sh';
      AProcess.Execute;
      AProcess.Free;
      {$else $IFDEF Windows}
         AppName := PChar(extractfilepath(Application.ExeName)+'Restart.exe') ;
         ShellExecute(form1.Handle,'open', AppName, pchar('/1'), nil, SW_SHOWNORMAL)
      {$endif}
     
Gruß, Michael

Stevie
Beiträge: 43
Registriert: Di 27. Feb 2024, 22:40

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Stevie »

Wie gesagt: solche Skripte überleben zunehmend das Ende des startenden Programms nicht mehr und werden, wenn so etwas wie CyberArk oder Wallix ins Spiel kommt, spätestens bei der Abmeldung weggeräumt.

Wahrscheinlich bräuchte man noch ein paar mehr Informationen zu den Anforderungen, zum Umfeld und zur gewünschten (auch zeitlichen) Robustheit...

Ich934
Lazarusforum e. V.
Beiträge: 317
Registriert: So 5. Mai 2019, 16:52
OS, Lazarus, FPC: ArchLinux und Windows mit FPCUPdeluxe (L: 2.0.X, FPC 3.2.0)
CPU-Target: x86_64, i386
Wohnort: Bayreuth

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Ich934 »

Hallo,

stimmt, es ist nohup. Tippfehler von mir und ja, das ist vorhanden. 8)

Es geht um ein Update-Programm. Die neue Version wird aus dem Internet heruntergeladen, ersetzt das Binary und dann soll (wenn gewünscht) das Programm gestartet werden.

Ich bekomme das hin in dem der Updater als eingefrorenes Programm weiter läuft oder aber indem das Hauptprogramm beendet wird, wenn der Updater beendet wird.

Das mit dem Skript werde ich mal testen. Es wäre hier egal, wenn das aufgeräumt wird. Ich würde das eh versuchen, im Temp-Verzeichnis zu erstellen.

cu tb
Tipp für PostgreSQL: www.pg-forum.de

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1436
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von fliegermichl »

Ich hab das bei mir so gelöst, daß ich immer ein Startprogramm habe, welches meine eigentliche Applikation startet.
Wenn die Applikation upgedated werden will, dann beendet diese sich mit einem bestimmten Errorlevel und das Startprogramm lädt dann das Update herunter, installiert es und startet die Anwendung erneut.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6216
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von af0815 »

Ich934 hat geschrieben:
Fr 15. Mär 2024, 09:39
Es geht um ein Update-Programm. Die neue Version wird aus dem Internet heruntergeladen, ersetzt das Binary und dann soll (wenn gewünscht) das Programm gestartet werden.

Ich bekomme das hin in dem der Updater als eingefrorenes Programm weiter läuft oder aber indem das Hauptprogramm beendet wird, wenn der Updater beendet wird.
Ich würde sagen, man sieht sich die Quellen von Lazarus und StartLazarus an, die machen das ganze ja auch mit Lazarus selbst und das Plattformunabhängig.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Warf
Beiträge: 1913
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Warf »

Nohup ist übrigens auch keine schwarze magie, sondern effektiv auch nur ein paar zeilen code: https://github.com/ahjragaas/busybox/bl ... ls/nohup.c

Im Grunde müssen nur 3 Operationen durchgeführt werden: 1. STDIN schließen oder aus einer datei pipen, 2. STDOUT schließen oder in eine Datei Pipen 3. HUP signal abfangen.

Grund dafür ist der folgende. Wenn du ein Programm startest, erbt das die "Konsole" des aufrufenden Prozesses. Wenn die Konsole geschlossen wird, wird ein HUP signal gesendet (Hang Up), und das standard verhalten davon ist das es den Prozess killt.
Bei einer Komandozeilenanwendung ist das tatsächlich weniger das Problem, da du hierbei ja ein "echtes" Terminal auf hast, und das wird erst geschlossen wenn du das Terminal Fenster schließt. Bei einer GUI Anwendung, allerdings ist das Terminal so zu sagen eine temporäre unsichtbare Instanz die mit dem GUI programm geöffnet wird, und sobald du es schließt geschlossen wird. Damit sobald das GUI programm stirbt, stirbt das Terminal und sendet HUP an alle anderen Prozesse die in diesem Kontext gestartet wurden.

Wenn man das HUP signal ignoriert, läuft der Prozess einfach weiter als wäre nichts passiert, das einzige Problem ist dann noch, das wenn das Terminal weg ist, alle lese und Schreibversuche darein natürlich nicht mehr Funktionieren und Fehler werfen und die meisten Programme crashen/sterben einfach. Daher muss das gehandled werden indem man STDOUT und STDIN irgendwie umleitet, z.B. in Dateien, oder nach /dev/null, damit werden outputs ignoriert, aber es wird kein Fehler geworfen.

Mit TProcess ist das vermutlich nicht so ganz einfach umzusetzen, da müsste man vermutlich schon selbst fork-execve bauen. Aber auch das ist für simple programme im Endeffekt nur ein 5 zeiler oder so.

Ich934
Lazarusforum e. V.
Beiträge: 317
Registriert: So 5. Mai 2019, 16:52
OS, Lazarus, FPC: ArchLinux und Windows mit FPCUPdeluxe (L: 2.0.X, FPC 3.2.0)
CPU-Target: x86_64, i386
Wohnort: Bayreuth

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Ich934 »

Hallo,

das hier ist jetzt meine Lösung, die genau das macht, was ich möchte...

Code: Alles auswählen

var
...
  {$IFDEF UNIX}
  starter: TStringList;
  {$ENDIF}
  {$IFDEF WINDOWS}
  AppName: PChar;
  {$ENDIF}
begin 
...
    {$IFDEF WINDOWS}
    AppName := PChar(ExtractFilePath(Application.ExeName) + Binary) ;
    ShellExecute(frmMain.Handle, 'open', AppName, pchar('/1'), nil, 1);
    {$ELSE}
    starter := TStringList.Create;
    starter.Add('nohup ' + ExtractFilePath(Application.ExeName) +
      Binary + ' >/dev/null 2>&1 &');
    starter.Add('disown');
    starter.Add('exit');
    starter.SaveToFile(Application.Location + PathDelim + 'startdetach');
    fpSystem('bash < ' + Application.Location + PathDelim + 'startdetach');
    deletefile(Application.Location + PathDelim + 'startdetach');
    starter.Free;
    {$ENDIF} 
Das Ganze ist eine Kombination aus verschiedenen Lösungen von hier.

Schöne Grüße
Tipp für PostgreSQL: www.pg-forum.de

Warf
Beiträge: 1913
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Warf »

Wenn du den umweg über bash machen willst, dann erstell kein script, und erst recht nicht auf der Platte (gibt temporäre dateien für sowas). Aber du kannst einfach -c verwenden:

Code: Alles auswählen

runcommand('/bin/bash', ['-c', 'nohup ' + ExtractFilePath(Application.ExeName) +
      Binary + ' >/dev/null 2>&1 &; disown; exit'], dummy);
PS: Wenn man deine anwendung in einen ordner mit dem namen '|| rm -rf ~ #' (erlaubter Name unter Linux) kopiert, wirds echt lustig.

Ich934
Lazarusforum e. V.
Beiträge: 317
Registriert: So 5. Mai 2019, 16:52
OS, Lazarus, FPC: ArchLinux und Windows mit FPCUPdeluxe (L: 2.0.X, FPC 3.2.0)
CPU-Target: x86_64, i386
Wohnort: Bayreuth

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Ich934 »

Moin,

ja, versteh deinen Einwand. Dein Snippet geht aber so leider nicht und ich verstehe nicht warum.

Es hängt am "&", welches das Programm ja freigibt. Ohne diesen funktioniert es ohne Probleme, was aber dazu führt, dass das Programm wieder hängt.

Folgendes funktioniert:

Code: Alles auswählen

runcommand('/bin/bash', ['-c', 'nohup ' + ExtractFilePath(Application.ExeName) +
      Binary + ' >/dev/null 2>&1; disown; exit'], dummy);
Aber halt mit der genannten Einschränkungen. Hat jemand hierfür eine Erklärung?

Ich habe es jetzt auch schon versucht, den ganzen Parameter in Anführungszeichen zu setzen. Das geht ja in der Bash. Klappt hier aber auch nicht.
Tipp für PostgreSQL: www.pg-forum.de

Warf
Beiträge: 1913
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Warf »

Weil ich dämlich bin, & ist bereits schon ein Kommandoterminierungssymbol (wie ;, && und ||), somit ist es natürlich ein fehler wenn man & und ; verwendet.

Code: Alles auswählen

runcommand('/bin/bash', ['-c', 'nohup ' + ExtractFilePath(Application.ExeName) +
      Binary + ' >/dev/null 2>&1 & disown; exit'], dummy);
Kurz zur Erklärung, es gibt 4 wege Kommandos zusammenzuschalten, ";" (oder neue zeile im bash script) warte das vorrige kommando durchgelaufen ist, und für dann das nächste aus, egal ob das davor funktioniert hat oder nicht. && führt das vorrige kommando aus und wartet, und macht das danach nur wenn das vorrige kommando erfolgreich war. || führt das erste kommando aus, wartet und führt das danach nur aus wenn das erste nicht erfolgreich war. & hingegen startet ein kommando und macht weiter bevor es überhaupt ein ergebnis gibt.

Daher macht &; keinen Sinn, da man bash Gleichzeitig sagt es soll nicht warten und warten.

Stevie
Beiträge: 43
Registriert: Di 27. Feb 2024, 22:40

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Stevie »

Versuch mal, den Langläufer mit 'coproc' aus einem Shell-Skript heraus zu starten, das Du dann wiederum aus Deinem Pascal-Programm startest. Bei mir funktioniert das. Also so:

langlaeufer.sh

Code: Alles auswählen

#!/bin/bash

for i in 1 2 3 4 5 6 7 8 9 0 ; do
  echo Durchlauf $i ... >> .langlaeufer.log
  sleep 5
done
launcher.sh

Code: Alles auswählen

#!/bin/bash

coproc ./langlaeufer.sh

exit
runit.pas

Code: Alles auswählen

{$mode objfpc}{$h+}
program runit;

uses
 sysutils, process;

var
  dummy : string;
begin
  writeln('Run It !');
  dummy := '';
  if runcommand('/bin/bash', ['-c','./launcher.sh'], dummy) then
    writeln('Erfolgreich.')
  else
    writeln('Fehler!');
end.
Das verlagert das Prozessmanagement in das Shell-Programm und kapselt die OS-spezifischen Aspekte gegenüber dem Pascal-Programm. Im Falle von Windows könnte man also einen 'launcher.bat' schreiben, der das dann entsprechend anders handhabt.

Ich934
Lazarusforum e. V.
Beiträge: 317
Registriert: So 5. Mai 2019, 16:52
OS, Lazarus, FPC: ArchLinux und Windows mit FPCUPdeluxe (L: 2.0.X, FPC 3.2.0)
CPU-Target: x86_64, i386
Wohnort: Bayreuth

Re: Externes Programm getrennt von Hauptprogramm ausführen?

Beitrag von Ich934 »

Warf hat geschrieben:
Sa 16. Mär 2024, 12:09
Daher macht &; keinen Sinn, da man bash Gleichzeitig sagt es soll nicht warten und warten.
Das war es! Vielen Dank! Damit geht es!
Tipp für PostgreSQL: www.pg-forum.de

Antworten