gitee.com/mirrors_u-root/u-root@v7.0.0+incompatible/pkg/kmodule/kmodule_linux.go (about) 1 // Copyright 2017-2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package kmodule interfaces with Linux kernel modules. 6 // 7 // kmodule allows loading and unloading kernel modules with dependencies, as 8 // well as locating them through probing. 9 package kmodule 10 11 import ( 12 "bufio" 13 "bytes" 14 "fmt" 15 "io" 16 "io/ioutil" 17 "os" 18 "path" 19 "path/filepath" 20 "strings" 21 22 "golang.org/x/sys/unix" 23 ) 24 25 // Flags to finit_module(2) / FileInit. 26 const ( 27 // Ignore symbol version hashes. 28 MODULE_INIT_IGNORE_MODVERSIONS = 0x1 29 30 // Ignore kernel version magic. 31 MODULE_INIT_IGNORE_VERMAGIC = 0x2 32 ) 33 34 // Init loads the kernel module given by image with the given options. 35 func Init(image []byte, opts string) error { 36 return unix.InitModule(image, opts) 37 } 38 39 // FileInit loads the kernel module contained by `f` with the given opts and 40 // flags. 41 // 42 // FileInit falls back to Init when the finit_module(2) syscall is not available. 43 func FileInit(f *os.File, opts string, flags uintptr) error { 44 err := unix.FinitModule(int(f.Fd()), opts, int(flags)) 45 if err == unix.ENOSYS { 46 if flags != 0 { 47 return err 48 } 49 50 // Fall back to regular init_module(2). 51 img, err := ioutil.ReadAll(f) 52 if err != nil { 53 return err 54 } 55 return Init(img, opts) 56 } 57 58 return err 59 } 60 61 // Delete removes a kernel module. 62 func Delete(name string, flags uintptr) error { 63 return unix.DeleteModule(name, int(flags)) 64 } 65 66 type modState uint8 67 68 const ( 69 unloaded modState = iota 70 loading 71 loaded 72 builtin 73 ) 74 75 type dependency struct { 76 state modState 77 deps []string 78 } 79 80 type depMap map[string]*dependency 81 82 // ProbeOpts contains optional parameters to Probe. 83 // 84 // An empty ProbeOpts{} should lead to the default behavior. 85 type ProbeOpts struct { 86 DryRunCB func(string) 87 RootDir string 88 KVer string 89 IgnoreProcMods bool 90 } 91 92 // Probe loads the given kernel module and its dependencies. 93 // It is calls ProbeOptions with the default ProbeOpts. 94 func Probe(name string, modParams string) error { 95 return ProbeOptions(name, modParams, ProbeOpts{}) 96 } 97 98 // ProbeOptions loads the given kernel module and its dependencies. 99 // This functions takes ProbeOpts. 100 func ProbeOptions(name, modParams string, opts ProbeOpts) error { 101 deps, err := genDeps(opts) 102 if err != nil { 103 return fmt.Errorf("could not generate dependency map %v", err) 104 } 105 106 modPath, err := findModPath(name, deps) 107 if err != nil { 108 return fmt.Errorf("could not find module path %q: %v", name, err) 109 } 110 111 dep := deps[modPath] 112 113 if dep.state == builtin || dep.state == loaded { 114 return nil 115 } 116 117 dep.state = loading 118 for _, d := range dep.deps { 119 if err := loadDeps(d, deps, opts); err != nil { 120 return err 121 } 122 } 123 if err := loadModule(modPath, modParams, opts); err != nil { 124 return err 125 } 126 127 return nil 128 } 129 130 func checkBuiltin(moduleDir string, deps depMap) error { 131 f, err := os.Open(filepath.Join(moduleDir, "modules.builtin")) 132 if os.IsNotExist(err) { 133 return nil 134 } else if err != nil { 135 return fmt.Errorf("could not open builtin file: %v", err) 136 } 137 defer f.Close() 138 139 scanner := bufio.NewScanner(f) 140 for scanner.Scan() { 141 txt := scanner.Text() 142 modPath := filepath.Join(moduleDir, strings.TrimSpace(txt)) 143 if deps[modPath] == nil { 144 deps[modPath] = new(dependency) 145 } 146 deps[modPath].state = builtin 147 } 148 149 return scanner.Err() 150 } 151 152 func genDeps(opts ProbeOpts) (depMap, error) { 153 deps := make(depMap) 154 rel := opts.KVer 155 156 if rel == "" { 157 var u unix.Utsname 158 if err := unix.Uname(&u); err != nil { 159 return nil, fmt.Errorf("could not get release (uname -r): %v", err) 160 } 161 rel = string(u.Release[:bytes.IndexByte(u.Release[:], 0)]) 162 } 163 164 var moduleDir string 165 for _, n := range []string{"/lib/modules", "/usr/lib/modules"} { 166 moduleDir = filepath.Join(opts.RootDir, n, strings.TrimSpace(rel)) 167 if _, err := os.Stat(moduleDir); err == nil { 168 break 169 } 170 } 171 172 f, err := os.Open(filepath.Join(moduleDir, "modules.dep")) 173 if err != nil { 174 return nil, fmt.Errorf("could not open dependency file: %v", err) 175 } 176 defer f.Close() 177 178 scanner := bufio.NewScanner(f) 179 for scanner.Scan() { 180 txt := scanner.Text() 181 nameDeps := strings.Split(txt, ":") 182 modPath, modDeps := nameDeps[0], nameDeps[1] 183 modPath = filepath.Join(moduleDir, strings.TrimSpace(modPath)) 184 185 var dependency dependency 186 if len(modDeps) > 0 { 187 for _, dep := range strings.Split(strings.TrimSpace(modDeps), " ") { 188 dependency.deps = append(dependency.deps, filepath.Join(moduleDir, dep)) 189 } 190 } 191 deps[modPath] = &dependency 192 } 193 194 if err := scanner.Err(); err != nil { 195 return nil, err 196 } 197 198 if err = checkBuiltin(moduleDir, deps); err != nil { 199 return nil, err 200 } 201 202 if !opts.IgnoreProcMods { 203 fm, err := os.Open("/proc/modules") 204 if err == nil { 205 defer fm.Close() 206 genLoadedMods(fm, deps) 207 } 208 } 209 210 return deps, nil 211 } 212 213 func findModPath(name string, m depMap) (string, error) { 214 for mp := range m { 215 if path.Base(mp) == name+".ko" { 216 return mp, nil 217 } 218 } 219 220 return "", fmt.Errorf("could not find path for module %q", name) 221 } 222 223 func loadDeps(path string, m depMap, opts ProbeOpts) error { 224 dependency, ok := m[path] 225 if !ok { 226 return fmt.Errorf("could not find dependency %q", path) 227 } 228 229 if dependency.state == loading { 230 return fmt.Errorf("circular dependency! %q already LOADING", path) 231 } else if (dependency.state == loaded) || (dependency.state == builtin) { 232 return nil 233 } 234 235 m[path].state = loading 236 237 for _, dep := range dependency.deps { 238 if err := loadDeps(dep, m, opts); err != nil { 239 return err 240 } 241 } 242 243 // done with dependencies, load module 244 if err := loadModule(path, "", opts); err != nil { 245 return err 246 } 247 m[path].state = loaded 248 249 return nil 250 } 251 252 func loadModule(path, modParams string, opts ProbeOpts) error { 253 if opts.DryRunCB != nil { 254 opts.DryRunCB(path) 255 return nil 256 } 257 258 f, err := os.Open(path) 259 if err != nil { 260 return err 261 } 262 defer f.Close() 263 264 if err := FileInit(f, modParams, 0); err != nil && err != unix.EEXIST { 265 return err 266 } 267 268 return nil 269 } 270 271 func genLoadedMods(r io.Reader, deps depMap) error { 272 scanner := bufio.NewScanner(r) 273 for scanner.Scan() { 274 arr := strings.Split(scanner.Text(), " ") 275 name := strings.Replace(arr[0], "_", "-", -1) 276 modPath, err := findModPath(name, deps) 277 if err != nil { 278 return fmt.Errorf("could not find module path %q: %v", name, err) 279 } 280 if deps[modPath] == nil { 281 deps[modPath] = new(dependency) 282 } 283 deps[modPath].state = loaded 284 } 285 return scanner.Err() 286 }