1
2
3
4
5 package oshi.software.os.unix.solaris;
6
7 import static oshi.software.os.OSProcess.State.INVALID;
8 import static oshi.software.os.OSService.State.RUNNING;
9 import static oshi.software.os.OSService.State.STOPPED;
10 import static oshi.util.Memoizer.defaultExpiration;
11
12 import java.io.File;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Set;
16 import java.util.function.Supplier;
17 import java.util.stream.Collectors;
18
19 import com.sun.jna.platform.unix.solaris.Kstat2;
20 import com.sun.jna.platform.unix.solaris.LibKstat.Kstat;
21
22 import oshi.annotation.concurrent.ThreadSafe;
23 import oshi.driver.linux.proc.ProcessStat;
24 import oshi.driver.unix.solaris.Who;
25 import oshi.jna.platform.unix.SolarisLibc;
26 import oshi.software.common.AbstractOperatingSystem;
27 import oshi.software.os.FileSystem;
28 import oshi.software.os.InternetProtocolStats;
29 import oshi.software.os.NetworkParams;
30 import oshi.software.os.OSProcess;
31 import oshi.software.os.OSService;
32 import oshi.software.os.OSSession;
33 import oshi.software.os.OSThread;
34 import oshi.util.Constants;
35 import oshi.util.ExecutingCommand;
36 import oshi.util.GlobalConfig;
37 import oshi.util.Memoizer;
38 import oshi.util.ParseUtil;
39 import oshi.util.platform.unix.solaris.KstatUtil;
40 import oshi.util.platform.unix.solaris.KstatUtil.KstatChain;
41 import oshi.util.tuples.Pair;
42
43
44
45
46
47 @ThreadSafe
48 public class SolarisOperatingSystem extends AbstractOperatingSystem {
49
50 private static final String VERSION;
51 private static final String BUILD_NUMBER;
52 static {
53 String[] split = ParseUtil.whitespaces.split(ExecutingCommand.getFirstAnswer("uname -rv"));
54 VERSION = split[0];
55 BUILD_NUMBER = split.length > 1 ? split[1] : "";
56 }
57
58 private static final boolean ALLOW_KSTAT2 = GlobalConfig.get(GlobalConfig.OSHI_OS_SOLARIS_ALLOWKSTAT2, true);
59
60
61
62
63 public static final boolean HAS_KSTAT2;
64 static {
65 Kstat2 lib = null;
66 try {
67 if (ALLOW_KSTAT2) {
68 lib = Kstat2.INSTANCE;
69 }
70 } catch (UnsatisfiedLinkError e) {
71
72 }
73 HAS_KSTAT2 = lib != null;
74 }
75
76 private static final Supplier<Pair<Long, Long>> BOOT_UPTIME = Memoizer
77 .memoize(SolarisOperatingSystem::queryBootAndUptime, defaultExpiration());
78
79 private static final long BOOTTIME = querySystemBootTime();
80
81 @Override
82 public String queryManufacturer() {
83 return "Oracle";
84 }
85
86 @Override
87 public Pair<String, OSVersionInfo> queryFamilyVersionInfo() {
88 return new Pair<>("SunOS", new OSVersionInfo(VERSION, "Solaris", BUILD_NUMBER));
89 }
90
91 @Override
92 protected int queryBitness(int jvmBitness) {
93 if (jvmBitness == 64) {
94 return 64;
95 }
96 return ParseUtil.parseIntOrDefault(ExecutingCommand.getFirstAnswer("isainfo -b"), 32);
97 }
98
99 @Override
100 public FileSystem getFileSystem() {
101 return new SolarisFileSystem();
102 }
103
104 @Override
105 public InternetProtocolStats getInternetProtocolStats() {
106 return new SolarisInternetProtocolStats();
107 }
108
109 @Override
110 public List<OSSession> getSessions() {
111 return USE_WHO_COMMAND ? super.getSessions() : Who.queryUtxent();
112 }
113
114 @Override
115 public OSProcess getProcess(int pid) {
116 List<OSProcess> procs = getProcessListFromProcfs(pid);
117 if (procs.isEmpty()) {
118 return null;
119 }
120 return procs.get(0);
121 }
122
123 @Override
124 public List<OSProcess> queryAllProcesses() {
125 return queryAllProcessesFromPrStat();
126 }
127
128 @Override
129 public List<OSProcess> queryChildProcesses(int parentPid) {
130 List<OSProcess> allProcs = queryAllProcessesFromPrStat();
131 Set<Integer> descendantPids = getChildrenOrDescendants(allProcs, parentPid, false);
132 return allProcs.stream().filter(p -> descendantPids.contains(p.getProcessID())).collect(Collectors.toList());
133 }
134
135 @Override
136 public List<OSProcess> queryDescendantProcesses(int parentPid) {
137 List<OSProcess> allProcs = queryAllProcessesFromPrStat();
138 Set<Integer> descendantPids = getChildrenOrDescendants(allProcs, parentPid, true);
139 return allProcs.stream().filter(p -> descendantPids.contains(p.getProcessID())).collect(Collectors.toList());
140 }
141
142 private List<OSProcess> queryAllProcessesFromPrStat() {
143 return getProcessListFromProcfs(-1);
144 }
145
146 private List<OSProcess> getProcessListFromProcfs(int pid) {
147 List<OSProcess> procs = new ArrayList<>();
148
149 File[] numericFiles = null;
150 if (pid < 0) {
151
152 File directory = new File("/proc");
153 numericFiles = directory.listFiles(file -> Constants.DIGITS.matcher(file.getName()).matches());
154 } else {
155
156 File pidFile = new File("/proc/" + pid);
157 if (pidFile.exists()) {
158 numericFiles = new File[1];
159 numericFiles[0] = pidFile;
160 }
161 }
162 if (numericFiles == null) {
163 return procs;
164 }
165
166
167 for (File pidFile : numericFiles) {
168 int pidNum = ParseUtil.parseIntOrDefault(pidFile.getName(), 0);
169 OSProcess proc = new SolarisOSProcess(pidNum, this);
170 if (proc.getState() != INVALID) {
171 procs.add(proc);
172 }
173 }
174 return procs;
175 }
176
177 @Override
178 public int getProcessId() {
179 return SolarisLibc.INSTANCE.getpid();
180 }
181
182 @Override
183 public int getProcessCount() {
184 return ProcessStat.getPidFiles().length;
185 }
186
187 @Override
188 public int getThreadId() {
189 return SolarisLibc.INSTANCE.thr_self();
190 }
191
192 @Override
193 public OSThread getCurrentThread() {
194 return new SolarisOSThread(getProcessId(), getThreadId());
195 }
196
197 @Override
198 public int getThreadCount() {
199 List<String> threadList = ExecutingCommand.runNative("ps -eLo pid");
200 if (!threadList.isEmpty()) {
201
202 return threadList.size() - 1;
203 }
204 return getProcessCount();
205 }
206
207 @Override
208 public long getSystemUptime() {
209 return querySystemUptime();
210 }
211
212 private static long querySystemUptime() {
213 if (HAS_KSTAT2) {
214
215 return BOOT_UPTIME.get().getB();
216 }
217 try (KstatChain kc = KstatUtil.openChain()) {
218 Kstat ksp = kc.lookup("unix", 0, "system_misc");
219 if (ksp != null && kc.read(ksp)) {
220
221 return ksp.ks_snaptime / 1_000_000_000L;
222 }
223 }
224 return 0L;
225 }
226
227 @Override
228 public long getSystemBootTime() {
229 return BOOTTIME;
230 }
231
232 private static long querySystemBootTime() {
233 if (HAS_KSTAT2) {
234
235 return BOOT_UPTIME.get().getA();
236 }
237 try (KstatChain kc = KstatUtil.openChain()) {
238 Kstat ksp = kc.lookup("unix", 0, "system_misc");
239 if (ksp != null && kc.read(ksp)) {
240 return KstatUtil.dataLookupLong(ksp, "boot_time");
241 }
242 }
243 return System.currentTimeMillis() / 1000L - querySystemUptime();
244 }
245
246 private static Pair<Long, Long> queryBootAndUptime() {
247 Object[] results = KstatUtil.queryKstat2("/misc/unix/system_misc", "boot_time", "snaptime");
248
249 long boot = results[0] == null ? System.currentTimeMillis() : (long) results[0];
250
251 long snap = results[1] == null ? 0L : (long) results[1] / 1_000_000_000L;
252
253 return new Pair<>(boot, snap);
254 }
255
256 @Override
257 public NetworkParams getNetworkParams() {
258 return new SolarisNetworkParams();
259 }
260
261 @Override
262 public List<OSService> getServices() {
263 List<OSService> services = new ArrayList<>();
264
265 List<String> legacySvcs = new ArrayList<>();
266 File dir = new File("/etc/init.d");
267 File[] listFiles;
268 if (dir.exists() && dir.isDirectory() && (listFiles = dir.listFiles()) != null) {
269 for (File f : listFiles) {
270 legacySvcs.add(f.getName());
271 }
272 }
273
274 List<String> svcs = ExecutingCommand.runNative("svcs -p");
275
276
277
278
279
280
281
282
283
284
285
286 for (String line : svcs) {
287 if (line.startsWith("online")) {
288 int delim = line.lastIndexOf(":/");
289 if (delim > 0) {
290 String name = line.substring(delim + 1);
291 if (name.endsWith(":default")) {
292 name = name.substring(0, name.length() - 8);
293 }
294 services.add(new OSService(name, 0, STOPPED));
295 }
296 } else if (line.startsWith(" ")) {
297 String[] split = ParseUtil.whitespaces.split(line.trim());
298 if (split.length == 3) {
299 services.add(new OSService(split[2], ParseUtil.parseIntOrDefault(split[1], 0), RUNNING));
300 }
301 } else if (line.startsWith("legacy_run")) {
302 for (String svc : legacySvcs) {
303 if (line.endsWith(svc)) {
304 services.add(new OSService(svc, 0, STOPPED));
305 break;
306 }
307 }
308 }
309 }
310 return services;
311 }
312 }