View Javadoc
1   /*
2    * Copyright 2016-2024 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.util.platform.mac;
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.mac.SystemB;
18  
19  /**
20   * Provides access to sysctl calls on macOS
21   */
22  @ThreadSafe
23  public final class SysctlUtil {
24  
25      private static final Logger LOG = LoggerFactory.getLogger(SysctlUtil.class);
26  
27      private static final String SYSCTL_FAIL = "Failed sysctl call: {}, Error code: {}";
28  
29      private SysctlUtil() {
30      }
31  
32      /**
33       * Executes a sysctl call with an int result
34       *
35       * @param name name of the sysctl
36       * @param def  default int value
37       * @return The int result of the call if successful; the default otherwise
38       */
39      public static int sysctl(String name, int def) {
40          return sysctl(name, def, true);
41      }
42  
43      /**
44       * Executes a sysctl call with an int result
45       *
46       * @param name       name of the sysctl
47       * @param def        default int value
48       * @param logWarning whether to log the warning if not available
49       * @return The int result of the call if successful; the default otherwise
50       */
51      public static int sysctl(String name, int def, boolean logWarning) {
52          int intSize = com.sun.jna.platform.mac.SystemB.INT_SIZE;
53          try (Memory p = new Memory(intSize); CloseableSizeTByReference size = new CloseableSizeTByReference(intSize)) {
54              if (0 != SystemB.INSTANCE.sysctlbyname(name, p, size, null, size_t.ZERO)) {
55                  if (logWarning) {
56                      LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
57                  }
58                  return def;
59              }
60              return p.getInt(0);
61          }
62      }
63  
64      /**
65       * Executes a sysctl call with a long result
66       *
67       * @param name name of the sysctl
68       * @param def  default long value
69       * @return The long result of the call if successful; the default otherwise
70       */
71      public static long sysctl(String name, long def) {
72          int uint64Size = com.sun.jna.platform.mac.SystemB.UINT64_SIZE;
73          try (Memory p = new Memory(uint64Size);
74                  CloseableSizeTByReference size = new CloseableSizeTByReference(uint64Size)) {
75              if (0 != SystemB.INSTANCE.sysctlbyname(name, p, size, null, size_t.ZERO)) {
76                  LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
77                  return def;
78              }
79              return p.getLong(0);
80          }
81      }
82  
83      /**
84       * Executes a sysctl call with a String result
85       *
86       * @param name name of the sysctl
87       * @param def  default String value
88       * @return The String result of the call if successful; the default otherwise
89       */
90      public static String sysctl(String name, String def) {
91          return sysctl(name, def, true);
92      }
93  
94      /**
95       * Executes a sysctl call with a String result
96       *
97       * @param name       name of the sysctl
98       * @param def        default String value
99       * @param logWarning whether to log the warning if not available
100      * @return The String result of the call if successful; the default otherwise
101      */
102     public static String sysctl(String name, String def, boolean logWarning) {
103         // Call first time with null pointer to get value of size
104         try (CloseableSizeTByReference size = new CloseableSizeTByReference()) {
105             if (0 != SystemB.INSTANCE.sysctlbyname(name, null, size, null, size_t.ZERO)) {
106                 if (logWarning) {
107                     LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
108                 }
109                 return def;
110             }
111             // Add 1 to size for null terminated string
112             try (Memory p = new Memory(size.longValue() + 1L)) {
113                 if (0 != SystemB.INSTANCE.sysctlbyname(name, p, size, null, size_t.ZERO)) {
114                     if (logWarning) {
115                         LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
116                     }
117                     return def;
118                 }
119                 return p.getString(0);
120             }
121         }
122     }
123 
124     /**
125      * Executes a sysctl call with a Structure result
126      *
127      * @param name   name of the sysctl
128      * @param struct structure for the result
129      * @return True if structure is successfuly populated, false otherwise
130      */
131     public static boolean sysctl(String name, Structure struct) {
132         try (CloseableSizeTByReference size = new CloseableSizeTByReference(struct.size())) {
133             if (0 != SystemB.INSTANCE.sysctlbyname(name, struct.getPointer(), size, null, size_t.ZERO)) {
134                 LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
135                 return false;
136             }
137         }
138         struct.read();
139         return true;
140     }
141 
142     /**
143      * Executes a sysctl call with a Pointer result
144      *
145      * @param name name of the sysctl
146      * @return An allocated memory buffer containing the result on success, null otherwise. Its value on failure is
147      *         undefined.
148      */
149     public static Memory sysctl(String name) {
150         try (CloseableSizeTByReference size = new CloseableSizeTByReference()) {
151             if (0 != SystemB.INSTANCE.sysctlbyname(name, null, size, null, size_t.ZERO)) {
152                 LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
153                 return null;
154             }
155             Memory m = new Memory(size.longValue());
156             if (0 != SystemB.INSTANCE.sysctlbyname(name, m, size, null, size_t.ZERO)) {
157                 LOG.warn(SYSCTL_FAIL, name, Native.getLastError());
158                 m.close();
159                 return null;
160             }
161             return m;
162         }
163     }
164 }