View Javadoc
1   /*
2    * Copyright 2016-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.unix.freebsd;
6   
7   import static oshi.util.Memoizer.memoize;
8   
9   import java.util.function.Supplier;
10  
11  import oshi.annotation.concurrent.Immutable;
12  import oshi.hardware.Baseboard;
13  import oshi.hardware.Firmware;
14  import oshi.hardware.common.AbstractComputerSystem;
15  import oshi.hardware.platform.unix.UnixBaseboard;
16  import oshi.util.Constants;
17  import oshi.util.ExecutingCommand;
18  import oshi.util.ParseUtil;
19  import oshi.util.Util;
20  import oshi.util.platform.unix.freebsd.BsdSysctlUtil;
21  import oshi.util.tuples.Quintet;
22  
23  /**
24   * Hardware data obtained from dmidecode.
25   */
26  @Immutable
27  final class FreeBsdComputerSystem extends AbstractComputerSystem {
28  
29      private final Supplier<Quintet<String, String, String, String, String>> manufModelSerialUuidVers = memoize(
30              FreeBsdComputerSystem::readDmiDecode);
31  
32      @Override
33      public String getManufacturer() {
34          return manufModelSerialUuidVers.get().getA();
35      }
36  
37      @Override
38      public String getModel() {
39          return manufModelSerialUuidVers.get().getB();
40      }
41  
42      @Override
43      public String getSerialNumber() {
44          return manufModelSerialUuidVers.get().getC();
45      }
46  
47      @Override
48      public String getHardwareUUID() {
49          return manufModelSerialUuidVers.get().getD();
50      }
51  
52      @Override
53      public Firmware createFirmware() {
54          return new FreeBsdFirmware();
55      }
56  
57      @Override
58      public Baseboard createBaseboard() {
59          return new UnixBaseboard(manufModelSerialUuidVers.get().getA(), manufModelSerialUuidVers.get().getB(),
60                  manufModelSerialUuidVers.get().getC(), manufModelSerialUuidVers.get().getE());
61      }
62  
63      private static Quintet<String, String, String, String, String> readDmiDecode() {
64          String manufacturer = null;
65          String model = null;
66          String serialNumber = null;
67          String uuid = null;
68          String version = null;
69  
70          // $ sudo dmidecode -t system
71          // # dmidecode 3.0
72          // Scanning /dev/mem for entry point.
73          // SMBIOS 2.7 present.
74          //
75          // Handle 0x0001, DMI type 1, 27 bytes
76          // System Information
77          // Manufacturer: Parallels Software International Inc.
78          // Product Name: Parallels Virtual Platform
79          // Version: None
80          // Serial Number: Parallels-47 EC 38 2A 33 1B 4C 75 94 0F F7 AF 86 63 C0
81          // C4
82          // UUID: 2A38EC47-1B33-854C-940F-F7AF8663C0C4
83          // Wake-up Type: Power Switch
84          // SKU Number: Undefined
85          // Family: Parallels VM
86          //
87          // Handle 0x0016, DMI type 32, 20 bytes
88          // System Boot Information
89          // Status: No errors detected
90  
91          final String manufacturerMarker = "Manufacturer:";
92          final String productNameMarker = "Product Name:";
93          final String serialNumMarker = "Serial Number:";
94          final String uuidMarker = "UUID:";
95          final String versionMarker = "Version:";
96  
97          // Only works with root permissions but it's all we've got
98          for (final String checkLine : ExecutingCommand.runNative("dmidecode -t system")) {
99              if (checkLine.contains(manufacturerMarker)) {
100                 manufacturer = checkLine.split(manufacturerMarker)[1].trim();
101             } else if (checkLine.contains(productNameMarker)) {
102                 model = checkLine.split(productNameMarker)[1].trim();
103             } else if (checkLine.contains(serialNumMarker)) {
104                 serialNumber = checkLine.split(serialNumMarker)[1].trim();
105             } else if (checkLine.contains(uuidMarker)) {
106                 uuid = checkLine.split(uuidMarker)[1].trim();
107             } else if (checkLine.contains(versionMarker)) {
108                 version = checkLine.split(versionMarker)[1].trim();
109             }
110         }
111         // If we get to end and haven't assigned, use fallback
112         if (Util.isBlank(serialNumber)) {
113             serialNumber = querySystemSerialNumber();
114         }
115         if (Util.isBlank(uuid)) {
116             uuid = BsdSysctlUtil.sysctl("kern.hostuuid", Constants.UNKNOWN);
117         }
118         return new Quintet<>(Util.isBlank(manufacturer) ? Constants.UNKNOWN : manufacturer,
119                 Util.isBlank(model) ? Constants.UNKNOWN : model,
120                 Util.isBlank(serialNumber) ? Constants.UNKNOWN : serialNumber,
121                 Util.isBlank(uuid) ? Constants.UNKNOWN : uuid, Util.isBlank(version) ? Constants.UNKNOWN : version);
122     }
123 
124     private static String querySystemSerialNumber() {
125         String marker = "system.hardware.serial =";
126         for (String checkLine : ExecutingCommand.runNative("lshal")) {
127             if (checkLine.contains(marker)) {
128                 return ParseUtil.getSingleQuoteStringValue(checkLine);
129             }
130         }
131         return Constants.UNKNOWN;
132     }
133 }