diskutil.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package diskinfo
  2. import (
  3. "errors"
  4. "path/filepath"
  5. "strings"
  6. "imuslab.com/bokofs/bokofsd/mod/diskinfo/blkid"
  7. "imuslab.com/bokofs/bokofsd/mod/diskinfo/df"
  8. "imuslab.com/bokofs/bokofsd/mod/diskinfo/fdisk"
  9. "imuslab.com/bokofs/bokofsd/mod/diskinfo/lsblk"
  10. )
  11. // GetAllDisks retrieves all disks on the system.
  12. func GetAllDisks() ([]*Disk, error) {
  13. allBlockDevices, err := lsblk.GetLSBLKOutput()
  14. if err != nil {
  15. return nil, err
  16. }
  17. disks := []*Disk{}
  18. for _, blockDevice := range allBlockDevices {
  19. if blockDevice.Type == "disk" {
  20. thisDisk, err := GetDiskInfo(blockDevice.Name)
  21. if err != nil {
  22. return nil, err
  23. }
  24. disks = append(disks, thisDisk)
  25. }
  26. }
  27. return disks, nil
  28. }
  29. // DevicePathIsValidDisk checks if the given device path is a disk.
  30. func DevicePathIsValidDisk(path string) bool {
  31. //Make sure the path has a prefix and a trailing slash
  32. if !strings.HasPrefix(path, "/dev/") {
  33. path = "/dev/" + path
  34. }
  35. path = strings.TrimSuffix(path, "/")
  36. allBlockDevices, err := lsblk.GetLSBLKOutput()
  37. if err != nil {
  38. return false
  39. }
  40. for _, blockDevice := range allBlockDevices {
  41. if "/dev/"+blockDevice.Name == path {
  42. return blockDevice.Type == "disk"
  43. }
  44. }
  45. return false
  46. }
  47. // DevicePathIsPartition checks if the given device path is a valid partition.
  48. func DevicePathIsValidPartition(path string) bool {
  49. //Make sure the path has a prefix and a trailing slash
  50. if !strings.HasPrefix(path, "/dev/") {
  51. path = "/dev/" + path
  52. }
  53. path = strings.TrimSuffix(path, "/")
  54. allBlockDevices, err := lsblk.GetLSBLKOutput()
  55. if err != nil {
  56. return false
  57. }
  58. for _, blockDevice := range allBlockDevices {
  59. if !strings.HasPrefix(path, "/dev/"+blockDevice.Name) {
  60. //Skip this block device
  61. //This is not a partition of this block device
  62. continue
  63. }
  64. for _, child := range blockDevice.Children {
  65. if "/dev/"+child.Name == path {
  66. //As there are too many partition types
  67. //We can only check if the block device is not a disk and exists
  68. return true
  69. }
  70. }
  71. }
  72. return false
  73. }
  74. // GetDiskInfo retrieves the disk information for a given disk name.
  75. // e.g. "sda"
  76. // for partitions, use the GetPartitionInfo function
  77. func GetDiskInfo(diskname string) (*Disk, error) {
  78. if diskname == "" {
  79. return nil, errors.New("disk name is empty")
  80. }
  81. //Make sure the diskname is something like sda
  82. diskname = strings.TrimPrefix(diskname, "/dev/")
  83. //Create a new disk object
  84. thisDisk := &Disk{
  85. Name: diskname,
  86. Size: 0,
  87. BlockType: "disk",
  88. Partitions: []*Partition{},
  89. }
  90. //Try to get the disk model and identifier
  91. diskInfo, err := fdisk.GetDiskModelAndIdentifier(diskname)
  92. if err == nil {
  93. thisDisk.Model = diskInfo.Model
  94. thisDisk.Identifier = diskInfo.Identifier
  95. thisDisk.DiskLabel = diskInfo.DiskLabel
  96. }
  97. //Calculation variables for total disk used space
  98. totalDiskUseSpace := int64(0)
  99. //Populate the partitions
  100. allBlockDevices, err := lsblk.GetLSBLKOutput()
  101. if err != nil {
  102. return nil, err
  103. }
  104. for _, blockDevice := range allBlockDevices {
  105. if blockDevice.Name == diskname {
  106. thisDisk.Size = blockDevice.Size
  107. for _, partition := range blockDevice.Children {
  108. //Get the partition information from blkid
  109. partition := &Partition{
  110. Name: partition.Name,
  111. Size: partition.Size,
  112. Path: filepath.Join("/dev", partition.Name),
  113. BlockType: partition.Type,
  114. MountPoint: partition.MountPoint,
  115. }
  116. //Get the partition ID
  117. blkInfo, err := blkid.GetPartitionIDFromDevicePath(partition.Name)
  118. if err == nil {
  119. partition.UUID = blkInfo.UUID
  120. partition.PartUUID = blkInfo.PartUUID
  121. partition.PartLabel = blkInfo.PartLabel
  122. partition.BlockSize = blkInfo.BlockSize
  123. partition.BlockType = blkInfo.Type
  124. partition.FsType = blkInfo.Type
  125. }
  126. //Get the disk usage information
  127. diskUsage, err := df.GetDiskUsageByPath(partition.Name)
  128. if err == nil {
  129. partition.Used = diskUsage.Used
  130. partition.Free = diskUsage.Available
  131. }
  132. thisDisk.Partitions = append(thisDisk.Partitions, partition)
  133. }
  134. }
  135. }
  136. //Calculate the total disk used space
  137. for _, partition := range thisDisk.Partitions {
  138. totalDiskUseSpace += partition.Used
  139. }
  140. thisDisk.Used = totalDiskUseSpace
  141. thisDisk.Free = thisDisk.Size - totalDiskUseSpace
  142. return thisDisk, nil
  143. }
  144. func GetPartitionInfo(partitionName string) (*Partition, error) {
  145. partition := &Partition{
  146. Name: partitionName,
  147. }
  148. partInfo, err := blkid.GetPartitionIDFromDevicePath(partitionName)
  149. if err == nil {
  150. partition.UUID = partInfo.UUID
  151. partition.PartUUID = partInfo.PartUUID
  152. partition.PartLabel = partInfo.PartLabel
  153. partition.BlockSize = partInfo.BlockSize
  154. partition.BlockType = partInfo.Type
  155. partition.FsType = partInfo.Type
  156. }
  157. //Get the disk usage information
  158. diskUsage, err := df.GetDiskUsageByPath(partitionName)
  159. if err == nil {
  160. partition.Used = diskUsage.Used
  161. partition.Free = diskUsage.Available
  162. partition.MountPoint = diskUsage.MountedOn
  163. }
  164. return partition, nil
  165. }
  166. // GetDevicePathFromPartitionID retrieves the device path for a given partition ID.
  167. func GetDevicePathFromPartitionID(diskID string) (string, error) {
  168. if diskID == "" {
  169. return "", errors.New("disk ID is empty")
  170. }
  171. // Try to get the block device info
  172. allBlockDevices, err := lsblk.GetLSBLKOutput()
  173. if err != nil {
  174. return "", err
  175. }
  176. for _, blockDevice := range allBlockDevices {
  177. //Check each of the children to see if there is a partition with the given ID
  178. for _, child := range blockDevice.Children {
  179. if child.Name == diskID {
  180. return child.Name, nil
  181. }
  182. }
  183. }
  184. return "", errors.New("disk ID not found")
  185. }