github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/osutil/udev/crawler/device.go (about) 1 package crawler 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strings" 11 12 "github.com/snapcore/snapd/osutil/udev/netlink" 13 ) 14 15 const ( 16 BASE_DEVPATH = "/sys/devices" 17 ) 18 19 type Device struct { 20 KObj string 21 Env map[string]string 22 } 23 24 // ExistingDevices return all plugged devices matched by the matcher 25 // All uevent files inside /sys/devices is crawled to match right env values 26 func ExistingDevices(queue chan Device, errors chan error, matcher netlink.Matcher) chan struct{} { 27 quit := make(chan struct{}, 1) 28 29 if matcher != nil { 30 if err := matcher.Compile(); err != nil { 31 errors <- fmt.Errorf("Wrong matcher, err: %v", err) 32 quit <- struct{}{} 33 return quit 34 } 35 } 36 37 go func() { 38 err := filepath.Walk(BASE_DEVPATH, func(path string, info os.FileInfo, err error) error { 39 select { 40 case <-quit: 41 return fmt.Errorf("abort signal receive") 42 default: 43 if err != nil { 44 return err 45 } 46 47 if info.IsDir() || info.Name() != "uevent" { 48 return nil 49 } 50 51 env, err := getEventFromUEventFile(path) 52 if err != nil { 53 return err 54 } 55 56 kObj := filepath.Dir(path) 57 58 // Append to env subsystem if existing 59 if link, err := os.Readlink(kObj + "/subsystem"); err == nil { 60 env["SUBSYSTEM"] = filepath.Base(link) 61 } 62 63 if matcher == nil || matcher.EvaluateEnv(env) { 64 65 queue <- Device{ 66 KObj: kObj, 67 Env: env, 68 } 69 } 70 return nil 71 } 72 }) 73 74 if err != nil { 75 errors <- err 76 } 77 close(queue) 78 }() 79 return quit 80 } 81 82 // getEventFromUEventFile return all env var define in file 83 // syntax: name=value for each line 84 // Fonction use for /sys/.../uevent files 85 func getEventFromUEventFile(path string) (rv map[string]string, err error) { 86 f, err := os.Open(path) 87 if err != nil { 88 return nil, err 89 } 90 91 defer f.Close() 92 93 data, err := ioutil.ReadAll(f) 94 if err != nil { 95 return nil, err 96 } 97 98 rv = make(map[string]string, 0) 99 buf := bufio.NewScanner(bytes.NewBuffer(data)) 100 101 var line string 102 for buf.Scan() { 103 line = buf.Text() 104 field := strings.SplitN(line, "=", 2) 105 if len(field) != 2 { 106 return 107 } 108 rv[field[0]] = field[1] 109 } 110 111 return 112 }