I have a problem with launching one program from another. Actually, there are no problems to run one program from another using TProcess, but my situation is a little unusual. I will try to explain what I need and what I have.
Raspberry Pi operating system (I test on a regular computer with Linux), laboratory equipment. There are two programs written in Lazarus with a graphical interface. "runner" is launched at system startup without command line parameters with normal user rights, without showing its window it starts another "sdu" program with root rights. When there is a need to exit this program, it runs "runner" again with the command line option "-?" and with normal user rights. Everything seems to work fine, but only once. If I use the button from the "runner" GUI, I try to start "sdu" again, but now it stops working. I used ChatGPT in writing the process launch code, tried various options, both launch via TProcess and process replacement via FpExecv() and similar functions.
Here is code for launch app from runner:
procedure TForm1.runApp(anApp: string; asRoot: boolean);
var
AProcess: TProcess;
I: integer;
DisplayVar: string;
begin
AProcess := TProcess.Create(nil);
try
AProcess.InheritHandles := False;
AProcess.Options := [poNoConsole, poWaitOnExit];
AProcess.ShowWindow := swoShow;
DisplayVar := GetEnvironmentVariable('DISPLAY');
if DisplayVar = '' then
DisplayVar := ':0';
AProcess.Environment.Add('DISPLAY=' + DisplayVar);
for I := 1 to GetEnvironmentVariableCount do
AProcess.Environment.Add(GetEnvironmentString(I));
if asRoot then
begin
AProcess.Executable := '/bin/bash';
AProcess.Parameters.Add('-c');
AProcess.Parameters.Add('sudo setsid ' + anApp + ' &');
end
else
begin
AProcess.Executable := '/bin/bash';
AProcess.Parameters.Add('-c');
AProcess.Parameters.Add('setsid ' + anApp + ' &');
end;
AProcess.Execute;
finally
AProcess.Free;
end;
end;
Another core for replace process from runner:
procedure ReplaceWithProgram(const ProgramPath: string; const Params: array of string);
var
Args: array of PChar;
I: integer;
begin
// Arguments for execv
SetLength(Args, Length(Params) + 2); // +2: for ProgramPath and nil in the end
Args[0] := PChar(ProgramPath);
for I := 0 to High(Params) do
Args[I + 1] := PChar(Params[I]);
Args[Length(Params) + 1] := nil;
// Replace current process
FpExecv(PChar(ProgramPath), @Args[0],envp);
// If we here FpExecV() won`t work
WriteLn(Format('Failed to replace process with "%s". Error: %d',
[ProgramPath, fpGetErrno]));
Halt(1);
end;
Code for run "runner" from "sdu" as regular user
procedure LaunchRunnerAsUser;
var
Process: TProcess;
begin
Process := TProcess.Create(nil);
try
Process.Executable := '/bin/bash';
Process.Parameters.Add('-c');
{$IFDEF DEBUG}
Process.Parameters.Add('runuser -l vadim -c "DISPLAY=:0 '+BaseAppPath+'runner -?" &');
{$ELSE}
Process.Parameters.Add('runuser -l pi -c "DISPLAY=:0 '+BaseAppPath+'runner -?" &');
{$ENDIF}
Process.Options := [poNoConsole];
Process.Execute;
finally
Process.Free;
end;
end;
After loading the system, the runner starts the sdu and finishes its work. After terminating the work, the sdu starts the runner again, but it is no longer possible to return to the sdu from it. I used both the first and the second method.
sdu must be executed with root rights, as it requires access to system resources.
What should I change to be able to run one program from another an unlimited number of times?