1
2
3
4
5 package oshi.driver.unix.aix;
6
7 import java.io.IOException;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.nio.file.Paths;
11 import java.util.ArrayList;
12 import java.util.LinkedHashMap;
13 import java.util.List;
14 import java.util.Locale;
15 import java.util.Map;
16
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19
20 import com.sun.jna.Memory;
21 import com.sun.jna.NativeLong;
22 import com.sun.jna.platform.unix.LibCAPI.size_t;
23 import com.sun.jna.platform.unix.LibCAPI.ssize_t;
24
25 import oshi.annotation.concurrent.ThreadSafe;
26 import oshi.jna.platform.unix.AixLibc;
27 import oshi.jna.platform.unix.AixLibc.AixLwpsInfo;
28 import oshi.jna.platform.unix.AixLibc.AixPsInfo;
29 import oshi.util.FileUtil;
30 import oshi.util.tuples.Pair;
31 import oshi.util.tuples.Triplet;
32
33
34
35
36 @ThreadSafe
37 public final class PsInfo {
38 private static final Logger LOG = LoggerFactory.getLogger(PsInfo.class);
39
40 private static final AixLibc LIBC = AixLibc.INSTANCE;
41
42
43
44 private static final long PAGE_SIZE = 4096L;
45
46 private PsInfo() {
47 }
48
49
50
51
52
53
54
55 public static AixPsInfo queryPsInfo(int pid) {
56 return new AixPsInfo(FileUtil.readAllBytesAsBuffer(String.format(Locale.ROOT, "/proc/%d/psinfo", pid)));
57 }
58
59
60
61
62
63
64
65
66 public static AixLwpsInfo queryLwpsInfo(int pid, int tid) {
67 return new AixLwpsInfo(
68 FileUtil.readAllBytesAsBuffer(String.format(Locale.ROOT, "/proc/%d/lwp/%d/lwpsinfo", pid, tid)));
69 }
70
71
72
73
74
75
76
77
78 public static Triplet<Integer, Long, Long> queryArgsEnvAddrs(int pid, AixPsInfo psinfo) {
79 if (psinfo != null) {
80 int argc = psinfo.pr_argc;
81
82 if (argc > 0) {
83 long argv = psinfo.pr_argv;
84 long envp = psinfo.pr_envp;
85 return new Triplet<>(argc, argv, envp);
86 }
87 LOG.trace("Failed argc sanity check: argc={}", argc);
88 return null;
89 }
90 LOG.trace("Failed to read psinfo file for pid: {} ", pid);
91 return null;
92 }
93
94
95
96
97
98
99
100
101 public static Pair<List<String>, Map<String, String>> queryArgsEnv(int pid, AixPsInfo psinfo) {
102 List<String> args = new ArrayList<>();
103 Map<String, String> env = new LinkedHashMap<>();
104
105
106 Triplet<Integer, Long, Long> addrs = queryArgsEnvAddrs(pid, psinfo);
107 if (addrs != null) {
108
109 String procas = "/proc/" + pid + "/as";
110 int fd = LIBC.open(procas, 0);
111 if (fd < 0) {
112 LOG.trace("No permission to read file: {} ", procas);
113 return new Pair<>(args, env);
114 }
115 try {
116
117 int argc = addrs.getA();
118 long argv = addrs.getB();
119 long envp = addrs.getC();
120
121
122 long increment;
123 Path p = Paths.get("/proc/" + pid + "/status");
124 try {
125 byte[] status = Files.readAllBytes(p);
126 if (status[17] == 1) {
127 increment = 8;
128 } else {
129 increment = 4;
130 }
131 } catch (IOException e) {
132 return new Pair<>(args, env);
133 }
134
135
136 try (Memory buffer = new Memory(PAGE_SIZE * 2)) {
137 size_t bufSize = new size_t(buffer.size());
138
139
140 long bufStart = conditionallyReadBufferFromStartOfPage(fd, buffer, bufSize, 0, argv);
141 long[] argPtr = new long[argc];
142 long argp = bufStart == 0 ? 0 : getOffsetFromBuffer(buffer, argv - bufStart, increment);
143 if (argp > 0) {
144 for (int i = 0; i < argc; i++) {
145 long offset = argp + i * increment;
146 bufStart = conditionallyReadBufferFromStartOfPage(fd, buffer, bufSize, bufStart, offset);
147 argPtr[i] = bufStart == 0 ? 0 : getOffsetFromBuffer(buffer, offset - bufStart, increment);
148 }
149 }
150
151
152
153 bufStart = conditionallyReadBufferFromStartOfPage(fd, buffer, bufSize, bufStart, envp);
154 List<Long> envPtrList = new ArrayList<>();
155 long addr = bufStart == 0 ? 0 : getOffsetFromBuffer(buffer, envp - bufStart, increment);
156 int limit = 500;
157 long offset = addr;
158 while (addr != 0 && --limit > 0) {
159 bufStart = conditionallyReadBufferFromStartOfPage(fd, buffer, bufSize, bufStart, offset);
160 long envPtr = bufStart == 0 ? 0 : getOffsetFromBuffer(buffer, offset - bufStart, increment);
161 if (envPtr != 0) {
162 envPtrList.add(envPtr);
163 }
164 offset += increment;
165 }
166
167
168 for (int i = 0; i < argPtr.length && argPtr[i] != 0; i++) {
169 bufStart = conditionallyReadBufferFromStartOfPage(fd, buffer, bufSize, bufStart, argPtr[i]);
170 if (bufStart != 0) {
171 String argStr = buffer.getString(argPtr[i] - bufStart);
172 if (!argStr.isEmpty()) {
173 args.add(argStr);
174 }
175 }
176 }
177
178
179 for (Long envPtr : envPtrList) {
180 bufStart = conditionallyReadBufferFromStartOfPage(fd, buffer, bufSize, bufStart, envPtr);
181 if (bufStart != 0) {
182 String envStr = buffer.getString(envPtr - bufStart);
183 int idx = envStr.indexOf('=');
184 if (idx > 0) {
185 env.put(envStr.substring(0, idx), envStr.substring(idx + 1));
186 }
187 }
188 }
189 }
190 } finally {
191 LIBC.close(fd);
192 }
193 }
194 return new Pair<>(args, env);
195 }
196
197
198
199
200
201
202
203
204
205
206
207
208 private static long conditionallyReadBufferFromStartOfPage(int fd, Memory buffer, size_t bufSize, long bufStart,
209 long addr) {
210
211 if (addr < bufStart || addr - bufStart > PAGE_SIZE) {
212 long newStart = Math.floorDiv(addr, PAGE_SIZE) * PAGE_SIZE;
213 ssize_t result = LIBC.pread(fd, buffer, bufSize, new NativeLong(newStart));
214
215 if (result.longValue() < PAGE_SIZE) {
216 LOG.debug("Failed to read page from address space: {} bytes read", result.longValue());
217 return 0;
218 }
219 return newStart;
220 }
221 return bufStart;
222 }
223
224 private static long getOffsetFromBuffer(Memory buffer, long offset, long increment) {
225 return increment == 8 ? buffer.getLong(offset) : buffer.getInt(offset);
226 }
227 }