github.com/jaypipes/ghw@v0.21.1/pkg/usb/usb_linux.go (about)

     1  // Use and distribution licensed under the Apache license version 2.
     2  //
     3  // See the COPYING file in the root project directory for full text.
     4  //
     5  
     6  package usb
     7  
     8  import (
     9  	"bufio"
    10  	"bytes"
    11  	"fmt"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/jaypipes/ghw/pkg/context"
    17  	"github.com/jaypipes/ghw/pkg/linuxpath"
    18  )
    19  
    20  func (i *Info) load() error {
    21  	var errs []error
    22  
    23  	i.Devices, errs = usbs(i.ctx)
    24  
    25  	if len(errs) == 0 {
    26  		return nil
    27  	}
    28  	return fmt.Errorf("error(s) happened during reading usb info: %+v", errs)
    29  }
    30  
    31  func fillUSBFromUevent(dir string, dev *Device) (err error) {
    32  	ueventFp, err := os.Open(filepath.Join(dir, "uevent"))
    33  	if err != nil {
    34  		return
    35  	}
    36  	defer func() {
    37  		err = ueventFp.Close()
    38  	}()
    39  
    40  	sc := bufio.NewScanner(ueventFp)
    41  	for sc.Scan() {
    42  		line := sc.Text()
    43  
    44  		splits := strings.SplitN(line, "=", 2)
    45  		if len(splits) != 2 {
    46  			continue
    47  		}
    48  
    49  		key := strings.ToUpper(splits[0])
    50  		val := splits[1]
    51  
    52  		switch key {
    53  		case "DRIVER":
    54  			dev.Driver = val
    55  		case "TYPE":
    56  			dev.Type = val
    57  		case "PRODUCT":
    58  			splits := strings.SplitN(val, "/", 3)
    59  			if len(splits) != 3 {
    60  				continue
    61  			}
    62  			dev.VendorID = splits[0]
    63  			dev.ProductID = splits[1]
    64  			dev.RevisionID = splits[2]
    65  		}
    66  	}
    67  	return nil
    68  }
    69  
    70  func slurp(path string) string {
    71  	bs, err := os.ReadFile(path)
    72  	if err != nil {
    73  		return ""
    74  	}
    75  
    76  	return string(bytes.TrimSpace(bs))
    77  }
    78  
    79  func usbs(ctx *context.Context) ([]*Device, []error) {
    80  	devs := make([]*Device, 0)
    81  	errs := []error{}
    82  
    83  	paths := linuxpath.New(ctx)
    84  	usbDevicesDirs, err := os.ReadDir(paths.SysBusUsbDevices)
    85  	if err != nil {
    86  		return devs, []error{err}
    87  	}
    88  
    89  	for _, dir := range usbDevicesDirs {
    90  		fullDir, err := os.Readlink(filepath.Join(paths.SysBusUsbDevices, dir.Name()))
    91  		if err != nil {
    92  			continue
    93  		}
    94  		if !filepath.IsAbs(fullDir) {
    95  			fullDir, err = filepath.Abs(filepath.Join(paths.SysBusUsbDevices, fullDir))
    96  			if err != nil {
    97  				continue
    98  			}
    99  		}
   100  
   101  		dev := Device{}
   102  
   103  		err = fillUSBFromUevent(fullDir, &dev)
   104  		if err != nil {
   105  			errs = append(errs, err)
   106  		}
   107  
   108  		dev.Interface = slurp(filepath.Join(fullDir, "interface"))
   109  		dev.Product = slurp(filepath.Join(fullDir, "product"))
   110  
   111  		devs = append(devs, &dev)
   112  	}
   113  
   114  	return devs, errs
   115  }