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