View Javadoc
1   /*
2    * Copyright 2021-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.driver.unix.openbsd.disk;
6   
7   import java.util.ArrayList;
8   import java.util.List;
9   
10  import oshi.annotation.concurrent.ThreadSafe;
11  import oshi.hardware.HWPartition;
12  import oshi.util.Constants;
13  import oshi.util.ExecutingCommand;
14  import oshi.util.ParseUtil;
15  import oshi.util.tuples.Pair;
16  import oshi.util.tuples.Quartet;
17  
18  /**
19   * Utility class parsing partition information from disklabel command
20   */
21  @ThreadSafe
22  public final class Disklabel {
23  
24      private Disklabel() {
25      }
26  
27      /**
28       * Gets disk and partition information
29       *
30       * @param diskName The disk to fetch partition information from
31       * @return A quartet containing the disk's name/label, DUID, size, and a list of partitions
32       */
33      public static Quartet<String, String, Long, List<HWPartition>> getDiskParams(String diskName) {
34          // disklabel (requires root) supports 15 configurable partitions, `a' through
35          // `p', excluding `c'.
36          // The `c' partition describes the entire physical disk.
37          // By convention, the `a' partition of the boot disk is the root
38          // partition, and the `b' partition of the boot disk is the swap partition,
39          // and the 'i' partition is usually the boot record
40  
41          // Create a list for all the other partitions
42          List<HWPartition> partitions = new ArrayList<>();
43          // Save some values to return to the caller to populate HWDiskStore values
44          String totalMarker = "total sectors:";
45          long totalSectors = 1L;
46          String bpsMarker = "bytes/sector:";
47          int bytesPerSector = 1;
48          String labelMarker = "label:";
49          String label = "";
50          String duidMarker = "duid:";
51          String duid = "";
52          for (String line : ExecutingCommand.runNative("disklabel -n " + diskName)) {
53              // Check for values in the header we need for the HWDiskstore
54              // # /dev/rsd1c:
55              // type: SCSI
56              // disk: SCSI disk
57              // label: Storage Device
58              // duid: 0000000000000000
59              // flags:
60              // bytes/sector: 512
61              // sectors/track: 63
62              // tracks/cylinder: 255
63              // sectors/cylinder: 16065
64              // cylinders: 976
65              // total sectors: 15693824
66              // boundstart: 0
67              // boundend: 15693824
68              // drivedata: 0
69              if (line.contains(totalMarker)) {
70                  totalSectors = ParseUtil.getFirstIntValue(line);
71              } else if (line.contains(bpsMarker)) {
72                  bytesPerSector = ParseUtil.getFirstIntValue(line);
73              } else if (line.contains(labelMarker)) {
74                  label = line.split(labelMarker)[1].trim();
75              } else if (line.contains(duidMarker)) {
76                  duid = line.split(duidMarker)[1].trim();
77              }
78              /*-
79              16 partitions:
80              #                size           offset  fstype [fsize bsize   cpg]
81                a:          2097152             1024  4.2BSD   2048 16384 12958 # /
82                b:         17023368          2098176    swap                    # none
83                c:        500118192                0  unused
84                d:          8388576         19121568  4.2BSD   2048 16384 12958 # /tmp
85                e:         41386752         27510144  4.2BSD   2048 16384 12958 # /var
86                f:          4194304         68896896  4.2BSD   2048 16384 12958 # /usr
87                g:          2097152         73091200  4.2BSD   2048 16384 12958 # /usr/X11R6
88                h:         20971520         75188352  4.2BSD   2048 16384 12958 # /usr/local
89                i:              960               64   MSDOS
90                j:          4194304         96159872  4.2BSD   2048 16384 12958 # /usr/src
91                k:         12582912        100354176  4.2BSD   2048 16384 12958 # /usr/obj
92                l:        387166336        112937088  4.2BSD   4096 32768 26062 # /home
93               Note size is in sectors
94               */
95              if (line.trim().indexOf(':') == 1) {
96                  // partition table values have a single letter followed by a colon
97                  String[] split = ParseUtil.whitespaces.split(line.trim(), 9);
98                  String name = split[0].substring(0, 1);
99                  // get major and minor from stat
100                 Pair<Integer, Integer> majorMinor = getMajorMinor(diskName, name);
101                 // add partitions
102                 if (split.length > 4) {
103                     partitions.add(new HWPartition(diskName + name, name, split[3], duid + "." + name,
104                             ParseUtil.parseLongOrDefault(split[1], 0L) * bytesPerSector, majorMinor.getA(),
105                             majorMinor.getB(), split.length > 5 ? split[split.length - 1] : ""));
106                 }
107             }
108         }
109         if (partitions.isEmpty()) {
110             return getDiskParamsNoRoot(diskName);
111         }
112         return new Quartet<>(label, duid, totalSectors * bytesPerSector, partitions);
113     }
114 
115     private static Quartet<String, String, Long, List<HWPartition>> getDiskParamsNoRoot(String diskName) {
116         List<HWPartition> partitions = new ArrayList<>();
117         for (String line : ExecutingCommand.runNative("df")) {
118             if (line.startsWith("/dev/" + diskName)) {
119                 String[] split = ParseUtil.whitespaces.split(line);
120                 String name = split[0].substring(5 + diskName.length());
121                 Pair<Integer, Integer> majorMinor = getMajorMinor(diskName, name);
122                 if (split.length > 5) {
123                     long partSize = ParseUtil.parseLongOrDefault(split[1], 1L) * 512L;
124                     partitions.add(new HWPartition(split[0], split[0].substring(5), Constants.UNKNOWN,
125                             Constants.UNKNOWN, partSize, majorMinor.getA(), majorMinor.getB(), split[5]));
126                 }
127             }
128         }
129         return new Quartet<>(Constants.UNKNOWN, Constants.UNKNOWN, 0L, partitions);
130     }
131 
132     private static Pair<Integer, Integer> getMajorMinor(String diskName, String name) {
133         int major = 0;
134         int minor = 0;
135         String majorMinor = ExecutingCommand.getFirstAnswer("stat -f %Hr,%Lr /dev/" + diskName + name);
136         int comma = majorMinor.indexOf(',');
137         if (comma > 0 && comma < majorMinor.length()) {
138             major = ParseUtil.parseIntOrDefault(majorMinor.substring(0, comma), 0);
139             minor = ParseUtil.parseIntOrDefault(majorMinor.substring(comma + 1), 0);
140         }
141         return new Pair<>(major, minor);
142     }
143 }