aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/subsystem/linux/subsystems.go
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2023-01-11 19:37:37 +0100
committerAleksandr Nogikh <wp32pw@gmail.com>2023-02-10 14:34:44 +0100
commit4c1f201b6fc2cc30625d3c706b1f45cc68ef0223 (patch)
tree57f61c8bbb0c9792e58f0b368539b390725edb4b /pkg/subsystem/linux/subsystems.go
parent2246b3b0ea578783224118ca3af660ecb0ebd2b6 (diff)
pkg/subsystem/linux: add the basic subsystem extraction code
Diffstat (limited to 'pkg/subsystem/linux/subsystems.go')
-rw-r--r--pkg/subsystem/linux/subsystems.go124
1 files changed, 124 insertions, 0 deletions
diff --git a/pkg/subsystem/linux/subsystems.go b/pkg/subsystem/linux/subsystems.go
new file mode 100644
index 000000000..b5ffa924c
--- /dev/null
+++ b/pkg/subsystem/linux/subsystems.go
@@ -0,0 +1,124 @@
+// Copyright 2023 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package linux
+
+import (
+ "fmt"
+ "io/fs"
+ "os"
+ "sort"
+
+ "github.com/google/syzkaller/pkg/subsystem/entity"
+)
+
+func ListFromRepo(repo string) ([]*entity.Subsystem, error) {
+ return listFromRepoInner(os.DirFS(repo), linuxSubsystemRules)
+}
+
+// listFromRepoInner allows for better testing.
+func listFromRepoInner(root fs.FS, rules *customRules) ([]*entity.Subsystem, error) {
+ records, err := getMaintainers(root)
+ if err != nil {
+ return nil, err
+ }
+ ctx := &linuxCtx{
+ root: root,
+ rawRecords: records,
+ extraRules: rules,
+ }
+ ctx.groupByList()
+ list, err := ctx.getSubsystems()
+ if err != nil {
+ return nil, err
+ }
+ // Sort subsystems by name to keep output consistent.
+ sort.Slice(list, func(i, j int) bool { return list[i].Name < list[j].Name })
+ // Sort path rules to keep output consistent.
+ for _, entity := range list {
+ sort.Slice(entity.PathRules, func(i, j int) bool {
+ a, b := entity.PathRules[i], entity.PathRules[j]
+ if a.IncludeRegexp != b.IncludeRegexp {
+ return a.IncludeRegexp < b.IncludeRegexp
+ }
+ return a.ExcludeRegexp < b.ExcludeRegexp
+ })
+ }
+ return list, nil
+}
+
+type linuxCtx struct {
+ root fs.FS
+ rawRecords []*maintainersRecord
+ extraRules *customRules
+}
+
+type subsystemCandidate struct {
+ records []*maintainersRecord
+ commonEmail string
+}
+
+func (ctx *linuxCtx) groupByList() []*subsystemCandidate {
+ perList := make(map[string][]*maintainersRecord)
+ for _, record := range ctx.rawRecords {
+ for _, list := range record.lists {
+ perList[list] = append(perList[list], record)
+ }
+ }
+ ret := []*subsystemCandidate{}
+ for email, list := range perList {
+ ret = append(ret, &subsystemCandidate{
+ commonEmail: email,
+ records: list,
+ })
+ }
+ return ret
+}
+
+func (ctx *linuxCtx) getSubsystems() ([]*entity.Subsystem, error) {
+ ret := []*entity.Subsystem{}
+ for _, raw := range ctx.groupByList() {
+ s := &entity.Subsystem{}
+ mergeRawRecords(s, raw.records)
+ ret = append(ret, s)
+ }
+ return ret, nil
+}
+
+func mergeRawRecords(subsystem *entity.Subsystem, records []*maintainersRecord) {
+ unique := func(list []string) []string {
+ m := make(map[string]struct{})
+ for _, s := range list {
+ m[s] = struct{}{}
+ }
+ ret := []string{}
+ for s := range m {
+ ret = append(ret, s)
+ }
+ return ret
+ }
+ var lists, maintainers []string
+ for _, record := range records {
+ rule := record.ToPathRule()
+ if !rule.IsEmpty() {
+ subsystem.PathRules = append(subsystem.PathRules, rule)
+ }
+ lists = append(lists, record.lists...)
+ maintainers = append(maintainers, record.maintainers...)
+ }
+ subsystem.Lists = unique(lists)
+ // But there's a risk that we collect too many unrelated maintainers, so
+ // let's only merge them if there are no lists.
+ if len(records) <= 1 {
+ subsystem.Maintainers = unique(maintainers)
+ }
+}
+
+func getMaintainers(root fs.FS) ([]*maintainersRecord, error) {
+ f, err := root.Open("MAINTAINERS")
+ if err != nil {
+ return nil, fmt.Errorf("failed to open the MAINTAINERS file: %w", err)
+ }
+ defer f.Close()
+ return parseLinuxMaintainers(f)
+}