1
2
3
4
5 package oshi.software.os.unix.freebsd;
6
7 import static oshi.software.os.OSService.State.RUNNING;
8 import static oshi.software.os.OSService.State.STOPPED;
9 import static oshi.software.os.OperatingSystem.ProcessFiltering.VALID_PROCESS;
10
11 import java.io.File;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Locale;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.function.Predicate;
20 import java.util.stream.Collectors;
21
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 import com.sun.jna.ptr.NativeLongByReference;
26
27 import oshi.annotation.concurrent.ThreadSafe;
28 import oshi.driver.unix.freebsd.Who;
29 import oshi.jna.platform.unix.FreeBsdLibc;
30 import oshi.jna.platform.unix.FreeBsdLibc.Timeval;
31 import oshi.software.common.AbstractOperatingSystem;
32 import oshi.software.os.FileSystem;
33 import oshi.software.os.InternetProtocolStats;
34 import oshi.software.os.NetworkParams;
35 import oshi.software.os.OSProcess;
36 import oshi.software.os.OSService;
37 import oshi.software.os.OSSession;
38 import oshi.software.os.OSThread;
39 import oshi.util.ExecutingCommand;
40 import oshi.util.ParseUtil;
41 import oshi.util.platform.unix.freebsd.BsdSysctlUtil;
42 import oshi.util.tuples.Pair;
43
44
45
46
47
48
49
50 @ThreadSafe
51 public class FreeBsdOperatingSystem extends AbstractOperatingSystem {
52
53 private static final Logger LOG = LoggerFactory.getLogger(FreeBsdOperatingSystem.class);
54
55 private static final long BOOTTIME = querySystemBootTime();
56
57
58
59
60 enum PsKeywords {
61 STATE, PID, PPID, USER, UID, GROUP, GID, NLWP, PRI, VSZ, RSS, ETIMES, SYSTIME, TIME, COMM, MAJFLT, MINFLT,
62 NVCSW, NIVCSW, ARGS;
63 }
64
65 static final String PS_COMMAND_ARGS = Arrays.stream(PsKeywords.values()).map(Enum::name)
66 .map(name -> name.toLowerCase(Locale.ROOT)).collect(Collectors.joining(","));
67
68 @Override
69 public String queryManufacturer() {
70 return "Unix/BSD";
71 }
72
73 @Override
74 public Pair<String, OSVersionInfo> queryFamilyVersionInfo() {
75 String family = BsdSysctlUtil.sysctl("kern.ostype", "FreeBSD");
76
77 String version = BsdSysctlUtil.sysctl("kern.osrelease", "");
78 String versionInfo = BsdSysctlUtil.sysctl("kern.version", "");
79 String buildNumber = versionInfo.split(":")[0].replace(family, "").replace(version, "").trim();
80
81 return new Pair<>(family, new OSVersionInfo(version, null, buildNumber));
82 }
83
84 @Override
85 protected int queryBitness(int jvmBitness) {
86 if (jvmBitness < 64 && ExecutingCommand.getFirstAnswer("uname -m").indexOf("64") == -1) {
87 return jvmBitness;
88 }
89 return 64;
90 }
91
92 @Override
93 public FileSystem getFileSystem() {
94 return new FreeBsdFileSystem();
95 }
96
97 @Override
98 public InternetProtocolStats getInternetProtocolStats() {
99 return new FreeBsdInternetProtocolStats();
100 }
101
102 @Override
103 public List<OSSession> getSessions() {
104 return USE_WHO_COMMAND ? super.getSessions() : Who.queryUtxent();
105 }
106
107 @Override
108 public List<OSProcess> queryAllProcesses() {
109 return getProcessListFromPS(-1);
110 }
111
112 @Override
113 public List<OSProcess> queryChildProcesses(int parentPid) {
114 List<OSProcess> allProcs = queryAllProcesses();
115 Set<Integer> descendantPids = getChildrenOrDescendants(allProcs, parentPid, false);
116 return allProcs.stream().filter(p -> descendantPids.contains(p.getProcessID())).collect(Collectors.toList());
117 }
118
119 @Override
120 public List<OSProcess> queryDescendantProcesses(int parentPid) {
121 List<OSProcess> allProcs = queryAllProcesses();
122 Set<Integer> descendantPids = getChildrenOrDescendants(allProcs, parentPid, true);
123 return allProcs.stream().filter(p -> descendantPids.contains(p.getProcessID())).collect(Collectors.toList());
124 }
125
126 @Override
127 public OSProcess getProcess(int pid) {
128 List<OSProcess> procs = getProcessListFromPS(pid);
129 if (procs.isEmpty()) {
130 return null;
131 }
132 return procs.get(0);
133 }
134
135 private List<OSProcess> getProcessListFromPS(int pid) {
136 String psCommand = "ps -awwxo " + PS_COMMAND_ARGS;
137 if (pid >= 0) {
138 psCommand += " -p " + pid;
139 }
140
141 Predicate<Map<PsKeywords, String>> hasKeywordArgs = psMap -> psMap.containsKey(PsKeywords.ARGS);
142 return ExecutingCommand.runNative(psCommand).stream().skip(1).parallel()
143 .map(proc -> ParseUtil.stringToEnumMap(PsKeywords.class, proc.trim(), ' ')).filter(hasKeywordArgs)
144 .map(psMap -> new FreeBsdOSProcess(
145 pid < 0 ? ParseUtil.parseIntOrDefault(psMap.get(PsKeywords.PID), 0) : pid, psMap, this))
146 .filter(VALID_PROCESS).collect(Collectors.toList());
147 }
148
149 @Override
150 public int getProcessId() {
151 return FreeBsdLibc.INSTANCE.getpid();
152 }
153
154 @Override
155 public int getProcessCount() {
156 List<String> procList = ExecutingCommand.runNative("ps -axo pid");
157 if (!procList.isEmpty()) {
158
159 return procList.size() - 1;
160 }
161 return 0;
162 }
163
164 @Override
165 public int getThreadId() {
166 NativeLongByReference pTid = new NativeLongByReference();
167 if (FreeBsdLibc.INSTANCE.thr_self(pTid) < 0) {
168 return 0;
169 }
170 return pTid.getValue().intValue();
171 }
172
173 @Override
174 public OSThread getCurrentThread() {
175 OSProcess proc = getCurrentProcess();
176 final int tid = getThreadId();
177 return proc.getThreadDetails().stream().filter(t -> t.getThreadId() == tid).findFirst()
178 .orElse(new FreeBsdOSThread(proc.getProcessID(), tid));
179 }
180
181 @Override
182 public int getThreadCount() {
183 int threads = 0;
184 for (String proc : ExecutingCommand.runNative("ps -axo nlwp")) {
185 threads += ParseUtil.parseIntOrDefault(proc.trim(), 0);
186 }
187 return threads;
188 }
189
190 @Override
191 public long getSystemUptime() {
192 return System.currentTimeMillis() / 1000 - BOOTTIME;
193 }
194
195 @Override
196 public long getSystemBootTime() {
197 return BOOTTIME;
198 }
199
200 private static long querySystemBootTime() {
201 Timeval tv = new Timeval();
202 if (!BsdSysctlUtil.sysctl("kern.boottime", tv) || tv.tv_sec == 0) {
203
204
205 return ParseUtil.parseLongOrDefault(
206 ExecutingCommand.getFirstAnswer("sysctl -n kern.boottime").split(",")[0].replaceAll("\\D", ""),
207 System.currentTimeMillis() / 1000);
208 }
209
210
211 return tv.tv_sec;
212 }
213
214 @Override
215 public NetworkParams getNetworkParams() {
216 return new FreeBsdNetworkParams();
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/init does not exist");
242 }
243 return services;
244 }
245 }