git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/sysinfo/storage.go (about) 1 // Copyright © 2016 Zlatko Čalušić 2 // 3 // Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. 4 5 package sysinfo 6 7 import ( 8 "bufio" 9 "io/ioutil" 10 "os" 11 "path" 12 "strconv" 13 "strings" 14 ) 15 16 // StorageDevice information. 17 type StorageDevice struct { 18 Name string `json:"name,omitempty"` 19 Driver string `json:"driver,omitempty"` 20 Vendor string `json:"vendor,omitempty"` 21 Model string `json:"model,omitempty"` 22 Serial string `json:"serial,omitempty"` 23 Size uint `json:"size,omitempty"` // device size in GB 24 } 25 26 func getSerial(name, fullpath string) (serial string) { 27 var f *os.File 28 var err error 29 30 // Modern location/format of the udev database. 31 if dev := slurpFile(path.Join(fullpath, "dev")); dev != "" { 32 if f, err = os.Open(path.Join("/run/udev/data", "b"+dev)); err == nil { 33 goto scan 34 } 35 } 36 37 // Legacy location/format of the udev database. 38 if f, err = os.Open(path.Join("/dev/.udev/db", "block:"+name)); err == nil { 39 goto scan 40 } 41 42 // No serial :( 43 return 44 45 scan: 46 defer f.Close() 47 48 s := bufio.NewScanner(f) 49 for s.Scan() { 50 if sl := strings.Split(s.Text(), "="); len(sl) == 2 { 51 if sl[0] == "E:ID_SERIAL_SHORT" { 52 serial = sl[1] 53 break 54 } 55 } 56 } 57 58 return 59 } 60 61 func (si *SysInfo) getStorageInfo() { 62 sysBlock := "/sys/block" 63 devices, err := ioutil.ReadDir(sysBlock) 64 if err != nil { 65 return 66 } 67 68 si.Storage = make([]StorageDevice, 0) 69 for _, link := range devices { 70 fullpath := path.Join(sysBlock, link.Name()) 71 dev, err := os.Readlink(fullpath) 72 if err != nil { 73 continue 74 } 75 76 if strings.HasPrefix(dev, "../devices/virtual/") { 77 continue 78 } 79 80 // We could filter all removable devices here, but some systems boot from USB flash disks, and then we 81 // would filter them, too. So, let's filter only floppies and CD/DVD devices, and see how it pans out. 82 if strings.HasPrefix(dev, "../devices/platform/floppy") || slurpFile(path.Join(fullpath, "device", "type")) == "5" { 83 continue 84 } 85 86 device := StorageDevice{ 87 Name: link.Name(), 88 Model: slurpFile(path.Join(fullpath, "device", "model")), 89 Serial: getSerial(link.Name(), fullpath), 90 } 91 92 if driver, err := os.Readlink(path.Join(fullpath, "device", "driver")); err == nil { 93 device.Driver = path.Base(driver) 94 } 95 96 if vendor := slurpFile(path.Join(fullpath, "device", "vendor")); !strings.HasPrefix(vendor, "0x") { 97 device.Vendor = vendor 98 } 99 100 size, _ := strconv.ParseUint(slurpFile(path.Join(fullpath, "size")), 10, 64) 101 device.Size = uint(size) / 1953125 // GiB 102 103 si.Storage = append(si.Storage, device) 104 } 105 }