-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmodprobe.go
183 lines (167 loc) · 4.18 KB
/
modprobe.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// The modprobe command loads and unloads Linux kernel modules and dependencies.
// It supports uncompressed, gzip, xz and zstd compressed module files.
//
// Usage:
// modprobe [options] MODULE [SYMBOL=VALUE]...
// modprobe [options] -a MODULE [MODULE]...
// modprobe [options] -r MODULE [MODULE]...
// modprobe [options] -D MODULE
// Options:
// -C string
// Config file (default "/etc/modprobe.conf")
// -D Print MODULE dependencies and exit
// -a Load multiple MODULEs
// -d string
// Modules root directory (default "/lib/modules")
// -n Dry-run
// -q Quiet
// -r Remove MODULE(s)
// -v Verbose
// -va
// Combines -v and -a
// Example:
// modprobe -v brd rd_size=32768 rd_nr=4
//
package main
import (
"compress/gzip"
"flag"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
"github.com/klauspost/compress/zstd"
"github.com/pmorjan/kmod"
"github.com/ulikunitz/xz"
"golang.org/x/sys/unix"
)
var (
all = flag.Bool("a", false, "Load multiple MODULEs")
deplist = flag.Bool("D", false, "Print MODULE dependencies and exit")
dryrun = flag.Bool("n", false, "Dry-run")
quiet = flag.Bool("q", false, "Quiet")
remove = flag.Bool("r", false, "Remove MODULE(s)")
rootdir = flag.String("d", "/lib/modules", "Modules root directory")
cfgfile = flag.String("C", "/etc/modprobe.conf", "Config file")
verbose = flag.Bool("v", false, "Verbose")
va = flag.Bool("va", false, "Combines -v and -a") // used via /proc/sys/kernel/modprobe
)
func usage() {
fmt.Fprint(os.Stderr, "Usage:\n")
fmt.Fprint(os.Stderr, " modprobe [options] MODULE [SYMBOL=VALUE]...\n")
fmt.Fprint(os.Stderr, " modprobe [options] -a MODULE [MODULE]...\n")
fmt.Fprint(os.Stderr, " modprobe [options] -r MODULE [MODULE]...\n")
fmt.Fprint(os.Stderr, " modprobe [options] -D MODULE\n")
fmt.Fprint(os.Stderr, "Options:\n")
flag.PrintDefaults()
fmt.Fprint(os.Stderr, "Example:\n")
fmt.Fprint(os.Stderr, " modprobe -v brd rd_size=32768 rd_nr=4\n")
os.Exit(1)
}
func main() {
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
if *quiet {
log.SetOutput(io.Discard)
}
if flag.NArg() < 1 || (*all || *va) && *remove {
usage()
}
opts := []kmod.Option{
kmod.SetConfigFile(*cfgfile),
kmod.SetRootDir(*rootdir),
kmod.SetInitFunc(modInitFunc),
}
if *dryrun {
opts = append(opts, kmod.SetDryrun())
}
if *verbose || *va {
opts = append(opts, kmod.SetVerbose())
}
k, err := kmod.New(opts...)
if err != nil {
log.Fatal(err)
}
args := flag.Args()
if *deplist {
list, err := k.Dependencies(args[0])
if err != nil {
log.Fatalf("Error: %v", err)
}
for _, v := range list {
fmt.Printf("insmod %s\n", v)
}
return
}
if *remove {
for _, name := range args {
if err := k.Unload(name); err != nil {
log.Fatalf("Error: %v", err)
}
}
return
}
if *all || *va {
for _, name := range args {
if err := k.Load(name, "", 0); err != nil {
log.Fatalf("Error: %v", err)
}
}
return
}
if err := k.Load(args[0], strings.Join(args[1:], " "), 0); err != nil {
log.Fatalf("Error: %v", err)
}
}
// modInitFunc supports uncompressed files and gzip and xz compressed files
func modInitFunc(path, params string, flags int) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
switch filepath.Ext(path) {
case ".gz":
rd, err := gzip.NewReader(f)
if err != nil {
return err
}
defer rd.Close()
return initModule(rd, params)
case ".xz":
rd, err := xz.NewReader(f)
if err != nil {
return err
}
return initModule(rd, params)
case ".zst":
rd, err := zstd.NewReader(f)
if err != nil {
return err
}
defer rd.Close()
return initModule(rd, params)
}
// uncompressed file, first try finitModule then initModule
if err := finitModule(int(f.Fd()), params); err != nil {
if err == unix.ENOSYS {
return initModule(f, params)
}
}
return nil
}
// finitModule inserts a module file via syscall finit_module(2)
func finitModule(fd int, params string) error {
return unix.FinitModule(fd, params, 0)
}
// initModule inserts a module via syscall init_module(2)
func initModule(rd io.Reader, params string) error {
buf, err := io.ReadAll(rd)
if err != nil {
return err
}
return unix.InitModule(buf, params)
}