diff options
Diffstat (limited to 'pkg/subsystem')
| -rw-r--r-- | pkg/subsystem/linux/maintainers.go | 144 | ||||
| -rw-r--r-- | pkg/subsystem/linux/maintainers_fuzz.go | 11 | ||||
| -rw-r--r-- | pkg/subsystem/linux/maintainers_test.go | 174 |
3 files changed, 329 insertions, 0 deletions
diff --git a/pkg/subsystem/linux/maintainers.go b/pkg/subsystem/linux/maintainers.go new file mode 100644 index 000000000..ce692bfd4 --- /dev/null +++ b/pkg/subsystem/linux/maintainers.go @@ -0,0 +1,144 @@ +// 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 ( + "bufio" + "fmt" + "io" + "net/mail" + "regexp" + "strings" + "unicode" +) + +// maintainersRecord represents a single raw record in the MAINTAINERS file. +type maintainersRecord struct { + name string + includePatterns []string + excludePatterns []string + regexps []string + lists []string + maintainers []string +} + +func parseLinuxMaintainers(content io.Reader) ([]*maintainersRecord, error) { + scanner := bufio.NewScanner(content) + // First skip the headers. + for scanner.Scan() { + line := scanner.Text() + if line == "Maintainers List" { + // Also skip ------. + scanner.Scan() + break + } + } + ml := &maintainersLexer{scanner: scanner} + ret := []*maintainersRecord{} +loop: + for { + item := ml.next() + switch v := item.(type) { + case recordTitle: + // The new subsystem begins. + ret = append(ret, &maintainersRecord{name: string(v)}) + case recordProperty: + if len(ret) == 0 { + return nil, fmt.Errorf("line %d: property without subsystem", ml.currentLine) + } + err := applyProperty(ret[len(ret)-1], &v) + if err != nil { + return nil, fmt.Errorf("line %d: failed to apply the property %#v: %w", + ml.currentLine, v, err) + } + case endOfFile: + break loop + } + } + if err := scanner.Err(); err != nil { + return nil, err + } + return ret, nil +} + +type maintainersLexer struct { + scanner *bufio.Scanner + currentLine int + inComment bool +} + +type recordTitle string +type recordProperty struct { + key string + value string +} +type endOfFile struct{} + +var propertyRe = regexp.MustCompile(`^([[:alpha:]]):\s+(.*).*$`) + +func (ml *maintainersLexer) next() interface{} { + for ml.scanner.Scan() { + ml.currentLine++ + rawLine := ml.scanner.Text() + line := strings.TrimSpace(rawLine) + if strings.HasPrefix(line, ".") { + ml.inComment = true + continue + } + // A comment continues to the next line(s) if they begin with a space character. + if ml.inComment && (line == "" || !unicode.IsSpace(rune(rawLine[0]))) { + ml.inComment = false + } + if ml.inComment || line == "" { + continue + } + // Now let's consider the possible line types. + if matches := propertyRe.FindStringSubmatch(line); matches != nil { + return recordProperty{key: matches[1], value: matches[2]} + } + return recordTitle(line) + } + return endOfFile{} +} + +func applyProperty(record *maintainersRecord, property *recordProperty) error { + switch property.key { + case "F": + record.includePatterns = append(record.includePatterns, property.value) + case "X": + record.excludePatterns = append(record.excludePatterns, property.value) + case "N": + if _, err := regexp.Compile(property.value); err != nil { + return fmt.Errorf("invalid regexp: %s", property.value) + } + record.regexps = append(record.regexps, property.value) + case "M": + value, err := parseEmail(property.value) + if err != nil { + return err + } + record.maintainers = append(record.maintainers, value) + case "L": + value, err := parseEmail(property.value) + if err != nil { + return err + } + record.lists = append(record.lists, value) + } + return nil +} + +func parseEmail(value string) (string, error) { + // Sometimes there happen extra symbols at the end of the line, + // let's make this parser more error tolerant. + pos := strings.LastIndexAny(value, ">)") + if pos >= 0 { + value = value[:pos+1] + } + addr, err := mail.ParseAddress(value) + if err != nil { + return "", err + } + return addr.Address, nil +} diff --git a/pkg/subsystem/linux/maintainers_fuzz.go b/pkg/subsystem/linux/maintainers_fuzz.go new file mode 100644 index 000000000..ebf4be524 --- /dev/null +++ b/pkg/subsystem/linux/maintainers_fuzz.go @@ -0,0 +1,11 @@ +// Copyright 2022 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 "bytes" + +func Fuzz(data []byte) int { + parseLinuxMaintainers(bytes.NewReader(data)) + return 0 +} diff --git a/pkg/subsystem/linux/maintainers_test.go b/pkg/subsystem/linux/maintainers_test.go new file mode 100644 index 000000000..874bdcaa7 --- /dev/null +++ b/pkg/subsystem/linux/maintainers_test.go @@ -0,0 +1,174 @@ +// 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 ( + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestLinuxMaintainers(t *testing.T) { + result, err := parseLinuxMaintainers( + strings.NewReader(maintainersSample), + ) + if err != nil { + t.Fatal(err) + } + targetResult := []*maintainersRecord{ + { + name: "3C59X NETWORK DRIVER", + includePatterns: []string{ + "Documentation/networking/device_drivers/ethernet/3com/vortex.rst", + "drivers/net/ethernet/3com/3c59x.c", + }, + lists: []string{"netdev@vger.kernel.org"}, + maintainers: []string{"email1@kernel.org"}, + }, + { + name: "ABI/API", + includePatterns: []string{ + "include/linux/syscalls.h", + "kernel/sys_ni.c", + }, + excludePatterns: []string{ + "include/uapi/", + "arch/*/include/uapi/", + }, + lists: []string{"linux-api@vger.kernel.org"}, + }, + { + name: "AD1889 ALSA SOUND DRIVER", + includePatterns: []string{"sound/pci/ad1889.*"}, + lists: []string{"linux-parisc@vger.kernel.org"}, + }, + { + name: "PVRUSB2 VIDEO4LINUX DRIVER", + includePatterns: []string{ + "Documentation/driver-api/media/drivers/pvrusb2*", + "drivers/media/usb/pvrusb2/", + }, + lists: []string{ + "pvrusb2@isely.net", + "linux-media@vger.kernel.org", + }, + maintainers: []string{"email2@kernel.org"}, + }, + { + name: "RISC-V ARCHITECTURE", + includePatterns: []string{"arch/riscv/"}, + regexps: []string{"riscv"}, + lists: []string{"linux-riscv@lists.infradead.org"}, + maintainers: []string{ + "email3@kernel.org", + "email4@kernel.org", + "email5@kernel.org", + }, + }, + { + name: "THE REST", + includePatterns: []string{"*", "*/"}, + lists: []string{"linux-kernel@vger.kernel.org"}, + maintainers: []string{"email6@kernel.org"}, + }, + } + if diff := cmp.Diff(targetResult, result, + cmp.AllowUnexported(maintainersRecord{})); diff != "" { + t.Fatal(diff) + } +} + +const maintainersSample = ` +List of maintainers and how to submit kernel changes +==================================================== + +Please try to follow the guidelines below. This will make things +easier on the maintainers. Not all of these guidelines matter for every +trivial patch so apply some common sense. + +Tips for patch submitters +------------------------- + +1. Always *test* your changes, however small, on at least 4 or + 5 people, preferably many more. + +< ... > + +8. Happy hacking. + +Descriptions of section entries and preferred order +--------------------------------------------------- + + M: *Mail* patches to: FullName <address@domain> + R: Designated *Reviewer*: FullName <address@domain> + These reviewers should be CCed on patches. +< ... > + K: *Content regex* (perl extended) pattern match in a patch or file. + For instance: + K: of_get_profile + matches patches or files that contain "of_get_profile" + K: \b(printk|pr_(info|err))\b + matches patches or files that contain one or more of the words + printk, pr_info or pr_err + One regex pattern per line. Multiple K: lines acceptable. + +Maintainers List +---------------- + +.. note:: When reading this list, please look for the most precise areas + first. When adding to this list, please keep the entries in + alphabetical order. + +3C59X NETWORK DRIVER +M: Name1 Surname <email1@kernel.org> +L: netdev@vger.kernel.org +S: Odd Fixes +F: Documentation/networking/device_drivers/ethernet/3com/vortex.rst +F: drivers/net/ethernet/3com/3c59x.c + +ABI/API +L: linux-api@vger.kernel.org +F: include/linux/syscalls.h +F: kernel/sys_ni.c +X: include/uapi/ +X: arch/*/include/uapi/ + +AD1889 ALSA SOUND DRIVER +L: linux-parisc@vger.kernel.org +S: Maintained +W: https://parisc.wiki.kernel.org/index.php/AD1889 +F: sound/pci/ad1889.* + +PVRUSB2 VIDEO4LINUX DRIVER +M: Name2 <email2@kernel.org> +L: pvrusb2@isely.net (subscribers-only) +L: linux-media@vger.kernel.org +S: Maintained +W: http://www.isely.net/pvrusb2/ +T: git git://linuxtv.org/media_tree.git +F: Documentation/driver-api/media/drivers/pvrusb2* +F: drivers/media/usb/pvrusb2/ + +RISC-V ARCHITECTURE +M: Name3 <email3@kernel.org> +M: Name4 <email4@kernel.org> +M: Name5 <email5@kernel.org> +L: linux-riscv@lists.infradead.org +S: Supported +Q: https://patchwork.kernel.org/project/linux-riscv/list/ +P: Documentation/riscv/patch-acceptance.rst +T: git git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git +F: arch/riscv/ +N: riscv +K: riscv + +THE REST +M: Name6 <email6@kernel.org> +L: linux-kernel@vger.kernel.org +S: Buried alive in reporters +T: git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git +F: * +F: */ +` |
