-
Notifications
You must be signed in to change notification settings - Fork 4
/
PalAdapter.cs
134 lines (106 loc) · 3.7 KB
/
PalAdapter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#if !HAS_TARGET_PLATFORM || LINUX
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static System.FormattableString;
namespace Gapotchenko.FX.Diagnostics.Pal.Linux
{
#if NET && !LINUX
[SupportedOSPlatform("linux")]
#endif
sealed class PalAdapter : IPalAdapter
{
PalAdapter()
{
}
public static PalAdapter Instance { get; } = new PalAdapter();
static string GetProcEntryFilePath(int pid, string name) => Invariant($"/proc/{pid}/{name}");
public int GetParentProcessId(Process process)
{
string filePath = GetProcEntryFilePath(process.Id, "status");
using var tr = File.OpenText(filePath);
for (; ; )
{
var line = tr.ReadLine();
if (line == null)
break;
const string key = "PPid:";
if (line.StartsWith(key, StringComparison.Ordinal))
{
#if TFF_MEMORY
var s = line.AsSpan(key.Length).Trim();
#else
var s = line.Substring(key.Length).Trim();
#endif
return int.Parse(s, provider: NumberFormatInfo.InvariantInfo);
}
}
throw new Exception(string.Format("PPid entry not found in \"{0}\" file.", filePath));
}
public string? GetProcessImageFileName(Process process) => null;
public void ReadProcessCommandLineArguments(Process process, out string? commandLine, out IEnumerable<string>? arguments)
{
commandLine = null;
arguments = ReadArguments(process.Id);
}
static IEnumerable<string> ReadArguments(int pid)
{
using var br = new ProcessBinaryReader(
File.OpenRead(GetProcEntryFilePath(pid, "cmdline")),
Encoding.UTF8);
for (; ; )
{
if (br.PeekChar() == -1)
{
// EOF
break;
}
yield return br.ReadCString();
}
}
public IReadOnlyDictionary<string, string> ReadProcessEnvironmentVariables(Process process)
{
using var br = new ProcessBinaryReader(
File.OpenRead(GetProcEntryFilePath(process.Id, "environ")),
Encoding.UTF8);
var env = new Dictionary<string, string>(StringComparer.InvariantCulture);
for (; ; )
{
if (br.PeekChar() == -1)
{
// End of environment block.
break;
}
var s = br.ReadCString();
int j = s.IndexOf('=');
if (j <= 0)
continue;
string name = s.Substring(0, j);
string value = s.Substring(j + 1);
env[name] = value;
}
return env;
}
public async Task<bool> TryInterruptProcessAsync(Process process, CancellationToken cancellationToken)
{
int pid = process.Id;
for (int i = 0; i < 5; ++i)
{
cancellationToken.ThrowIfCancellationRequested();
int result = NativeMethods.kill(pid, NativeMethods.SIGINT);
if (result == -1)
return false;
if (await process.WaitForExitAsync(100, cancellationToken).ConfigureAwait(false))
return true;
}
return false;
}
}
}
#endif