Em um sistema de teste do Centos 7 via
$ sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm
$ sudo yum install dotnet-sdk-2.1
que resulta em dotnet-sdk-2.1-2.1.400-1.x86_64
sendo instalado, em seguida, com o código de teste
using System;
using System.Diagnostics;
using System.ComponentModel;
namespace myApp {
class Program {
static void Main(string[] args) {
var process = new Process();
process.EnableRaisingEvents = true; // to avoid [defunct] sh processes
process.StartInfo.FileName = "/var/tmp/foo";
process.StartInfo.Arguments = "";
process.StartInfo.UseShellExecute = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForExit(10000);
if (process.HasExited) {
Console.WriteLine("Exit code: " + process.ExitCode);
} else {
Console.WriteLine("Child process still running after 10 seconds");
}
}
}
}
e um script shell como /var/tmp/foo
a strace
pare e mostre que /var/tmp/foo
é executado através de xdg-open
, o que no meu sistema faz ... Não sei o que, parece uma complicação desnecessária.
$ strace -o foo -f dotnet run
Child process still running after 10 seconds
^C
$ grep /var/tmp/foo foo
25907 execve("/usr/bin/xdg-open", ["/usr/bin/xdg-open", "/var/tmp/foo"], [/* 37 vars */] <unfinished ...>
...
uma solução mais simples é simplesmente exec
um programa que por sua vez pode ser um script de shell que faz o que você quer, o que para o .NET requer não usar o shell:
process.StartInfo.UseShellExecute = false;
com esse conjunto, o strace
mostra que /var/tmp/foo
está sendo executado por meio de uma chamada (muito mais simples) execve(2)
:
26268 stat("/var/tmp/foo", {st_mode=S_IFREG|0755, st_size=37, ...}) = 0
26268 access("/var/tmp/foo", X_OK) = 0
26275 execve("/var/tmp/foo", ["/var/tmp/foo"], [/* 37 vars */] <unfinished ...>
e esse .NET se recusa a sair:
$ strace -o foo -f dotnet run
Child process still running after 10 seconds
^C^C^C^C^C^C^C^C
porque foo
se substitui por algo que ignora a maioria dos sinais (notavelmente não USR2
, ou há sempre KILL
(mas evite usar isso!)):
$ cat /var/tmp/foo
#!/bin/sh
exec /var/tmp/stayin-alive
$ cat /var/tmp/stayin-alive
#!/usr/bin/perl
use Sys::Syslog;
for my $s (qw(HUP INT QUIT PIPE ALRM TERM CHLD USR1)) {
$SIG{$s} = \&shandle;
}
openlog( 'stayin-alive', 'ndelay,pid', LOG_USER );
while (1) {
syslog LOG_NOTICE, "oh oh oh oh oh stayin alive";
sleep 7;
}
sub shandle {
syslog LOG_NOTICE, "nice try - @_";
}
daemonize
Com um processo que se desassocia do pai e um script de shell que executa alguns comandos (espero que equivalentes para o seu pretendido apt-get update; apt-get upgrade
)
$ cat /var/tmp/a-few-things
#!/bin/sh
sleep 17 ; echo a >/var/tmp/output ; echo b >/var/tmp/output
podemos modificar o programa .NET para executar /var/tmp/solitary /var/tmp/a-few-things
process.StartInfo.FileName = "/var/tmp/solitary";
process.StartInfo.Arguments = "/var/tmp/a-few-things";
process.StartInfo.UseShellExecute = false;
que, quando executado, faz com que o programa .NET saia rapidamente
$ dotnet run
Exit code: 0
e, eventualmente, o arquivo /var/tmp/output
contém duas linhas escritas por um processo que não foi eliminado quando o programa .NET foi removido.
Você provavelmente deve salvar a saída dos comandos do APT em algum lugar, e também pode precisar de algo para que duas (ou mais!) atualizações não sejam necessárias
tentando ser executado ao mesmo tempo, etc. Esta versão não pára para perguntas e ignora qualquer TERM
sinais ( INT
também pode precisar ser ignorado).
#!/bin/sh
trap '' TERM
set -e
apt-get --yes update
apt-get --yes upgrade