View Javadoc
1   /*
2    * Copyright 2021-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.util.platform.unix.openbsd;
6   
7   import org.slf4j.Logger;
8   import org.slf4j.LoggerFactory;
9   
10  import com.sun.jna.Memory;
11  import com.sun.jna.Native;
12  import com.sun.jna.Structure;
13  import com.sun.jna.platform.unix.LibCAPI.size_t;
14  
15  import oshi.annotation.concurrent.ThreadSafe;
16  import oshi.jna.ByRef.CloseableSizeTByReference;
17  import oshi.jna.platform.unix.OpenBsdLibc;
18  import oshi.util.ExecutingCommand;
19  import oshi.util.ParseUtil;
20  
21  /**
22   * Provides access to sysctl calls on OpenBSD
23   */
24  @ThreadSafe
25  public final class OpenBsdSysctlUtil {
26  
27      private static final String SYSCTL_N = "sysctl -n ";
28  
29      private static final Logger LOG = LoggerFactory.getLogger(OpenBsdSysctlUtil.class);
30  
31      private static final String SYSCTL_FAIL = "Failed sysctl call: {}, Error code: {}";
32  
33      private OpenBsdSysctlUtil() {
34      }
35  
36      /**
37       * Executes a sysctl call with an int result
38       *
39       * @param name name of the sysctl
40       * @param def  default int value
41       * @return The int result of the call if successful; the default otherwise
42       */
43      public static int sysctl(int[] name, int def) {
44          int intSize = OpenBsdLibc.INT_SIZE;
45          try (Memory p = new Memory(intSize); CloseableSizeTByReference size = new CloseableSizeTByReference(intSize)) {
46              if (0 != OpenBsdLibc.INSTANCE.sysctl(name, name.length, p, size, null, size_t.ZERO)) {
47                  LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
48                  return def;
49              }
50              return p.getInt(0);
51          }
52      }
53  
54      /**
55       * Executes a sysctl call with a long result
56       *
57       * @param name name of the sysctl
58       * @param def  default long value
59       * @return The long result of the call if successful; the default otherwise
60       */
61      public static long sysctl(int[] name, long def) {
62          int uint64Size = OpenBsdLibc.UINT64_SIZE;
63          try (Memory p = new Memory(uint64Size);
64                  CloseableSizeTByReference size = new CloseableSizeTByReference(uint64Size)) {
65              if (0 != OpenBsdLibc.INSTANCE.sysctl(name, name.length, p, size, null, size_t.ZERO)) {
66                  LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
67                  return def;
68              }
69              return p.getLong(0);
70          }
71      }
72  
73      /**
74       * Executes a sysctl call with a String result
75       *
76       * @param name name of the sysctl
77       * @param def  default String value
78       * @return The String result of the call if successful; the default otherwise
79       */
80      public static String sysctl(int[] name, String def) {
81          // Call first time with null pointer to get value of size
82          try (CloseableSizeTByReference size = new CloseableSizeTByReference()) {
83              if (0 != OpenBsdLibc.INSTANCE.sysctl(name, name.length, null, size, null, size_t.ZERO)) {
84                  LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
85                  return def;
86              }
87              // Add 1 to size for null terminated string
88              try (Memory p = new Memory(size.longValue() + 1L)) {
89                  if (0 != OpenBsdLibc.INSTANCE.sysctl(name, name.length, p, size, null, size_t.ZERO)) {
90                      LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
91                      return def;
92                  }
93                  return p.getString(0);
94              }
95          }
96      }
97  
98      /**
99       * Executes a sysctl call with a Structure result
100      *
101      * @param name   name of the sysctl
102      * @param struct structure for the result
103      * @return True if structure is successfuly populated, false otherwise
104      */
105     public static boolean sysctl(int[] name, Structure struct) {
106         try (CloseableSizeTByReference size = new CloseableSizeTByReference(struct.size())) {
107             if (0 != OpenBsdLibc.INSTANCE.sysctl(name, name.length, struct.getPointer(), size, null, size_t.ZERO)) {
108                 LOG.error(SYSCTL_FAIL, name, Native.getLastError());
109                 return false;
110             }
111         }
112         struct.read();
113         return true;
114     }
115 
116     /**
117      * Executes a sysctl call with a Pointer result
118      *
119      * @param name name of the sysctl
120      * @return An allocated memory buffer containing the result on success, null otherwise. Its value on failure is
121      *         undefined.
122      */
123     public static Memory sysctl(int[] name) {
124         try (CloseableSizeTByReference size = new CloseableSizeTByReference()) {
125             if (0 != OpenBsdLibc.INSTANCE.sysctl(name, name.length, null, size, null, size_t.ZERO)) {
126                 LOG.error(SYSCTL_FAIL, name, Native.getLastError());
127                 return null;
128             }
129             Memory m = new Memory(size.longValue());
130             if (0 != OpenBsdLibc.INSTANCE.sysctl(name, name.length, m, size, null, size_t.ZERO)) {
131                 LOG.error(SYSCTL_FAIL, name, Native.getLastError());
132                 m.close();
133                 return null;
134             }
135             return m;
136         }
137     }
138 
139     /*
140      * Backup versions with command parsing
141      */
142 
143     /**
144      * Executes a sysctl call with an int result
145      *
146      * @param name name of the sysctl
147      * @param def  default int value
148      * @return The int result of the call if successful; the default otherwise
149      */
150     public static int sysctl(String name, int def) {
151         return ParseUtil.parseIntOrDefault(ExecutingCommand.getFirstAnswer(SYSCTL_N + name), def);
152     }
153 
154     /**
155      * Executes a sysctl call with a long result
156      *
157      * @param name name of the sysctl
158      * @param def  default long value
159      * @return The long result of the call if successful; the default otherwise
160      */
161     public static long sysctl(String name, long def) {
162         return ParseUtil.parseLongOrDefault(ExecutingCommand.getFirstAnswer(SYSCTL_N + name), def);
163     }
164 
165     /**
166      * Executes a sysctl call with a String result
167      *
168      * @param name name of the sysctl
169      * @param def  default String value
170      * @return The String result of the call if successful; the default otherwise
171      */
172     public static String sysctl(String name, String def) {
173         String v = ExecutingCommand.getFirstAnswer(SYSCTL_N + name);
174         if (null == v || v.isEmpty()) {
175             return def;
176         }
177         return v;
178     }
179 }