C#/mono: Obtenha a lista de processos filhos no Windows e Linux
Pergunta
Eu tenho o código abaixo para obter uma lista de processos filhos no Windows interop'ing com o NTDLL. Existe um equivalente a 'NtQueryInformationProcess' no Linux, que me obtém o ID do processo dos pais de um processo especificado (como PBI.IritedFromuniqueProcessId)? Eu preciso que o código seja executado no Linux através do Mono, então espero esperar que eu precise alterar apenas a peça em que recebo o ID do processo pai para que o código permaneça principalmente no Windows.
public IList< Process > GetChildren( Process parent )
{
List< Process > children = new List< Process >();
Process[] processes = Process.GetProcesses();
foreach (Process p in processes)
{
ProcessBasicInformation pbi = new ProcessBasicInformation();
try
{
uint bytesWritten;
NtQueryInformationProcess(p.Handle,
0, ref pbi, (uint)Marshal.SizeOf(pbi),
out bytesWritten); // == 0 is OK
if (pbi.InheritedFromUniqueProcessId == parent.Id)
children.AddRange(GetChildren(p));
}
catch
{
}
}
return children;
}
Solução
Uma maneira de encontrar todos os filhos de um determinado processo no Linux é fazer algo assim dentro de seu para cada:
string line;
using (StreamReader reader = new StreamReader ("/proc/" + p.Id + "/stat")) {
line = reader.ReadLine ();
}
string [] parts = line.Split (new char [] {' '}, 5); // Only interested in field at position 3
if (parts.Legth >= 4) {
int ppid = Int32.Parse (parts [3]);
if (ppid == parent.Id) {
// Found a children
}
}
Para obter mais informações sobre o que/proc/[id]/stat contém, consulte a página manual para 'proc'. Você também deve adicionar uma tentativa/captura em torno do 'usando' porque o processo pode morrer antes de abrirmos o arquivo, etc ...
Outras dicas
Na verdade, há um problema na resposta de Gonzalo, se o nome do processo tiver espaços. Este código funciona para mim:
public static int GetParentProcessId(int processId)
{
string line;
using (StreamReader reader = new StreamReader ("/proc/" + processId + "/stat"))
line = reader.ReadLine ();
int endOfName = line.LastIndexOf(')');
string [] parts = line.Substring(endOfName).Split (new char [] {' '}, 4);
if (parts.Length >= 3)
{
int ppid = Int32.Parse (parts [2]);
return ppid;
}
return -1;
}