1
2
3
4
5 package oshi.software.os.unix.openbsd;
6
7 import static oshi.jna.platform.unix.OpenBsdLibc.CTL_KERN;
8 import static oshi.jna.platform.unix.OpenBsdLibc.KERN_OSRELEASE;
9 import static oshi.jna.platform.unix.OpenBsdLibc.KERN_OSTYPE;
10 import static oshi.jna.platform.unix.OpenBsdLibc.KERN_VERSION;
11 import static oshi.software.os.OSService.State.RUNNING;
12 import static oshi.software.os.OSService.State.STOPPED;
13
14 import java.io.File;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Locale;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.stream.Collectors;
23
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import oshi.annotation.concurrent.ThreadSafe;
28 import oshi.jna.platform.unix.OpenBsdLibc;
29 import oshi.software.common.AbstractOperatingSystem;
30 import oshi.software.os.FileSystem;
31 import oshi.software.os.InternetProtocolStats;
32 import oshi.software.os.NetworkParams;
33 import oshi.software.os.OSProcess;
34 import oshi.software.os.OSService;
35 import oshi.software.os.OSThread;
36 import oshi.util.ExecutingCommand;
37 import oshi.util.ParseUtil;
38 import oshi.util.platform.unix.openbsd.OpenBsdSysctlUtil;
39 import oshi.util.tuples.Pair;
40
41
42
43
44
45 @ThreadSafe
46 public class OpenBsdOperatingSystem extends AbstractOperatingSystem {
47
48 private static final Logger LOG = LoggerFactory.getLogger(OpenBsdOperatingSystem.class);
49
50 private static final long BOOTTIME = querySystemBootTime();
51
52
53
54
55 enum PsKeywords {
56 STATE, PID, PPID, USER, UID, GROUP, GID, PRI, VSZ, RSS, ETIME, CPUTIME, COMM, MAJFLT, MINFLT, NVCSW, NIVCSW,
57 ARGS;
58 }
59
60 static final String PS_COMMAND_ARGS = Arrays.stream(PsKeywords.values()).map(Enum::name)
61 .map(name -> name.toLowerCase(Locale.ROOT)).collect(Collectors.joining(","));
62
63 @Override
64 public String queryManufacturer() {
65 return "Unix/BSD";
66 }
67
68 @Override
69 public Pair<String, OSVersionInfo> queryFamilyVersionInfo() {
70 int[] mib = new int[2];
71 mib[0] = CTL_KERN;
72 mib[1] = KERN_OSTYPE;
73 String family = OpenBsdSysctlUtil.sysctl(mib, "OpenBSD");
74 mib[1] = KERN_OSRELEASE;
75 String version = OpenBsdSysctlUtil.sysctl(mib, "");
76 mib[1] = KERN_VERSION;
77 String versionInfo = OpenBsdSysctlUtil.sysctl(mib, "");
78 String buildNumber = versionInfo.split(":")[0].replace(family, "").replace(version, "").trim();
79
80 return new Pair<>(family, new OSVersionInfo(version, null, buildNumber));
81 }
82
83 @Override
84 protected int queryBitness(int jvmBitness) {
85 if (jvmBitness < 64 && ExecutingCommand.getFirstAnswer("uname -m").indexOf("64") == -1) {
86 return jvmBitness;
87 }
88 return 64;
89 }
90
91 @Override
92 public FileSystem getFileSystem() {
93 return new OpenBsdFileSystem();
94 }
95
96 @Override
97 public InternetProtocolStats getInternetProtocolStats() {
98 return new OpenBsdInternetProtocolStats();
99 }
100
101 @Override
102 public List<OSProcess> queryAllProcesses() {
103 return getProcessListFromPS(-1);
104 }
105
106 @Override
107 public List<OSProcess> queryChildProcesses(int parentPid) {
108 List<OSProcess> allProcs = queryAllProcesses();
109 Set<Integer> descendantPids = getChildrenOrDescendants(allProcs, parentPid, false);
110 return allProcs.stream().filter(p -> descendantPids.contains(p.getProcessID())).collect(Collectors.toList());
111 }
112
113 @Override
114 public List<OSProcess> queryDescendantProcesses(int parentPid) {
115 List<OSProcess> allProcs = queryAllProcesses();
116 Set<Integer> descendantPids = getChildrenOrDescendants(allProcs, parentPid, true);
117 return allProcs.stream().filter(p -> descendantPids.contains(p.getProcessID())).collect(Collectors.toList());
118 }
119
120 @Override
121 public OSProcess getProcess(int pid) {
122 List<OSProcess> procs = getProcessListFromPS(pid);
123 if (procs.isEmpty()) {
124 return null;
125 }
126 return procs.get(0);
127 }
128
129 private List<OSProcess> getProcessListFromPS(int pid) {
130 List<OSProcess> procs = new ArrayList<>();
131
132
133 String psCommand = "ps -awwxo " + PS_COMMAND_ARGS;
134 if (pid >= 0) {
135 psCommand += " -p " + pid;
136 }
137 List<String> procList = ExecutingCommand.runNative(psCommand);
138 if (procList.isEmpty() || procList.size() < 2) {
139 return procs;
140 }
141
142
143 procList.remove(0);
144
145 for (String proc : procList) {
146 Map<PsKeywords, String> psMap = ParseUtil.stringToEnumMap(PsKeywords.class, proc.trim(), ' ');
147
148 if (psMap.containsKey(PsKeywords.ARGS)) {
149 procs.add(new OpenBsdOSProcess(
150 pid < 0 ? ParseUtil.parseIntOrDefault(psMap.get(PsKeywords.PID), 0) : pid, psMap, this));
151 }
152 }
153 return procs;
154 }
155
156 @Override
157 public int getProcessId() {
158 return OpenBsdLibc.INSTANCE.getpid();
159 }
160
161 @Override
162 public int getProcessCount() {
163 List<String> procList = ExecutingCommand.runNative("ps -axo pid");
164 if (!procList.isEmpty()) {
165
166 return procList.size() - 1;
167 }
168 return 0;
169 }
170
171 @Override
172 public int getThreadId() {
173 return OpenBsdLibc.INSTANCE.getthrid();
174 }
175
176 @Override
177 public OSThread getCurrentThread() {
178 OSProcess proc = getCurrentProcess();
179 final int tid = getThreadId();
180 return proc.getThreadDetails().stream().filter(t -> t.getThreadId() == tid).findFirst()
181 .orElse(new OpenBsdOSThread(proc.getProcessID(), tid));
182 }
183
184 @Override
185 public int getThreadCount() {
186
187
188
189 List<String> threadList = ExecutingCommand.runNative("ps -axHo tid");
190 if (!threadList.isEmpty()) {
191
192 return threadList.size() - 1;
193 }
194 return 0;
195 }
196
197 @Override
198 public long getSystemUptime() {
199 return System.currentTimeMillis() / 1000 - BOOTTIME;
200 }
201
202 @Override
203 public long getSystemBootTime() {
204 return BOOTTIME;
205 }
206
207 private static long querySystemBootTime() {
208
209 return ParseUtil.parseLongOrDefault(
210 ExecutingCommand.getFirstAnswer("sysctl -n kern.boottime").split(",")[0].replaceAll("\\D", ""),
211 System.currentTimeMillis() / 1000);
212 }
213
214 @Override
215 public NetworkParams getNetworkParams() {
216 return new OpenBsdNetworkParams();
217 }
218
219 @Override
220 public List<OSService> getServices() {
221
222 List<OSService> services = new ArrayList<>();
223 Set<String> running = new HashSet<>();
224 for (OSProcess p : getChildProcesses(1, ProcessFiltering.ALL_PROCESSES, ProcessSorting.PID_ASC, 0)) {
225 OSService s = new OSService(p.getName(), p.getProcessID(), RUNNING);
226 services.add(s);
227 running.add(p.getName());
228 }
229
230 File dir = new File("/etc/rc.d");
231 File[] listFiles;
232 if (dir.exists() && dir.isDirectory() && (listFiles = dir.listFiles()) != null) {
233 for (File f : listFiles) {
234 String name = f.getName();
235 if (!running.contains(name)) {
236 OSService s = new OSService(name, 0, STOPPED);
237 services.add(s);
238 }
239 }
240 } else {
241 LOG.error("Directory: /etc/rc.d does not exist");
242 }
243 return services;
244 }
245 }