26 Commits
1.0.2 ... 1.2

Author SHA1 Message Date
Clayton Craft
7a61e5126c Add /usr/bin/unudhcpd to initfs (MR 13)
This will replace the busybox dhcp server.

With this change, mkinitfs depends on the 'unudhcpd' packge in Alpine to
provide the binary at /usr/bin/unudhcpd.
2021-11-21 12:56:56 -08:00
Clayton Craft
0925cbd8ac bootDeploy: ignore suffixes added by boot-deploy when copying kernel (MR 11)
The glob might result in a vmlinuz-* filename that causes mkinitfs to
copy a modified kernel file to the boot-deploy working directory. This
excludes files that boot-deploy has touched from being copied/used by
boot-deploy
2021-10-03 18:07:36 -07:00
Minecrell
866f17b86f getModuleDeps: replace Split() loop with ReplaceAllString() (MR 12)
This should do the same as far as I can tell :)
2021-09-20 15:14:19 -07:00
Minecrell
15e99c3658 getModulesDep: disallow regex submatches (MR 12)
At the moment modules in modules.dep are matched even on a submatch
e.g. looking up "msm" ends up matching "snd-soc-msm8916-digital.ko"
instead of "msm.ko". To fix this, disallow submatches using ^ and $.
2021-09-20 15:14:05 -07:00
bo41
6400871749 CI: rename ci folder to consistent naming (MR 10)
part of https://gitlab.com/postmarketOS/postmarketos/-/issues/26
2021-09-16 21:54:53 -07:00
Clayton Craft
829009250c tests: add getModuleDep testing 2021-09-13 14:36:52 -07:00
Clayton Craft
d2fe03affc getModulesDep: use regex for searching module names in modules.dep
Fixes an issue where some modules might have both - and _ in the name...
Also refactored this to make testing easier.
2021-09-13 14:36:51 -07:00
Clayton Craft
febc162491 deviceinfo: add tests for new parser (MR 4)
An earlier revision of this patch had test for invalid lines, but I
decided to remove it because deviceinfo is sourced by so many things in
pmOS that it should be /very/ obvious that there are invalid lines or
other garbage in the file.

I also tried to make the parser fairly forgiving if it does encounter
things that don't meet the deviceinfo "spec", so that mkinitfs will try
as hard as it can to make an initfs.
2021-09-09 20:20:41 -07:00
Clayton Craft
d9f29af446 deviceinfo: implement a new simple parser (MR 4)
This replaces an external toml library with a simple parser for
unmarshalling a deviceinfo.
2021-09-09 20:20:41 -07:00
Newbyte
003e04eaf2 Remove redundant nil check (MR 8) 2021-09-09 20:15:39 -07:00
Clayton Craft
723517eb57 getInitfsModules: don't fail if kernel modules dir does not exist (MR 7)
This directory doesn't exist all the time, e.g. if the kernel was built
without modules or no modules were installed for some reason. Assume the
kernel package knows what it is doing and just print a message that
might be helpful if the kernel package ends up not knowing what it is
doing.
2021-09-09 20:12:27 -07:00
Clayton Craft
5dfd1e3787 use flag module from std lib for parsing cmdline args
The getopt thing was an experiment, and I'd rather lose external
dependencies than use getopt-like parsing especially since the only
argument this app takes is largely for testing/development purposes
only.
2021-09-04 23:51:26 -07:00
Clayton Craft
b9bea671fa main/getInitfsModules: remove superfluous continues
See: #6
2021-09-04 23:51:26 -07:00
Clayton Craft
bcced6bc10 fix lint issues from staticcheck
Specifically this fixes failures: ST1005, S1028, S1011

See #6
2021-09-04 22:43:55 -07:00
Clayton Craft
9b4b1c3320 createInitfsRootDirs: remove unused function 2021-09-04 22:33:11 -07:00
Clayton Craft
7e3268a9c8 ci: add staticcheck to linting
See #6
2021-09-04 22:32:11 -07:00
Clayton Craft
8128877bcb ci: use alpine linux edge image for linting/building
staticcheck isn't available in a stable release of Alpine Linux yet...
2021-09-04 22:21:05 -07:00
Clayton Craft
adec7cfe07 main: replace os.exit with return
See: #6
2021-09-03 22:47:03 -07:00
Clayton Craft
5b6cf42e10 main: add context for fatal errors
See: #6
2021-09-03 22:47:03 -07:00
Clayton Craft
001baa29bf main/stripExts: simplify implementation
See: #6
2021-09-03 22:47:03 -07:00
Clayton Craft
7bf5ce967f archive: remove unused checksum function 2021-09-03 22:47:03 -07:00
Clayton Craft
4293c887f8 Deviceinfo: replace toml lib, improve struct member names
See: #6
2021-09-03 22:47:02 -07:00
Clayton Craft
dc586f61fc archive/AddFile: add missing error check
See: #6
2021-09-03 22:42:31 -07:00
Clayton Craft
4538e7d46b Fix copyright text in Go source files
Apparently the space after is important or Go will consider the
copyright comments as package documentation.

See: #6
2021-09-03 22:42:30 -07:00
Clayton Craft
13a3ba36bd archive/checksum: do not try to close fd if open() failed
See #6
2021-09-03 22:42:23 -07:00
Clayton Craft
9c7e647f9e archive: remove testing of gzip archive
It has been determined that this test isn't really necessary. busybox
gzip is probably not going to break (and would be discovered elsewhere
too if it does...)

fixes #4
2021-09-03 16:32:12 -07:00
11 changed files with 333 additions and 206 deletions

13
.ci/check_linting.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
echo "### Running gofmt..."
files="$(gofmt -l .)"
if [ ! -z "$files" ]; then
# run gofmt to print out the diff of what needs to be changed
gofmt -d -e .
exit 1
fi
echo "### Running staticcheck..."
staticcheck ./...

View File

@@ -1,7 +1,7 @@
---
# global settings
image: alpine:latest
image: alpine:edge
stages:
- lint
@@ -27,9 +27,11 @@ gofmt linting:
allow_failure: true
<<: *only-default
before_script:
- apk -q add go
# specific mirror used because staticcheck hasn't made it to the other mirrors yet...
- apk -q update --repository http://dl-4.alpinelinux.org/alpine/edge/testing
- apk -q add --repository http://dl-4.alpinelinux.org/alpine/edge/testing go staticcheck
script:
- .gitlab-ci/check_gofmt.sh
- .ci/check_linting.sh
build:
stage: build

View File

@@ -1,11 +0,0 @@
#!/bin/sh
files="$(gofmt -l .)"
[ -z "$files" ] && exit 0
# run gofmt to print out the diff of what needs to be changed
gofmt -d -e .
exit 1

2
go.mod
View File

@@ -3,8 +3,6 @@ module gitlab.com/postmarketOS/postmarketos-mkinitfs
go 1.16
require (
git.sr.ht/~sircmpwn/getopt v0.0.0-20201218204720-9961a9c6298f
github.com/BurntSushi/toml v0.4.0
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e
github.com/klauspost/compress v1.13.3 // indirect
github.com/klauspost/pgzip v1.2.5

21
go.sum
View File

@@ -1,30 +1,9 @@
git.sr.ht/~sircmpwn/getopt v0.0.0-20201218204720-9961a9c6298f h1:f5axCdaRzGDCihN3o1Lq0ydn0VlkhY+11G0JOyY5qss=
git.sr.ht/~sircmpwn/getopt v0.0.0-20201218204720-9961a9c6298f/go.mod h1:wMEGFFFNuPos7vHmWXfszqImLppbc0wEhh6JBfJIUgw=
github.com/BurntSushi/toml v0.3.2-0.20210614224209-34d990aa228d/go.mod h1:2QZjSXA5e+XyFeCAxxtL8Z4StYUsTquL8ODGPR3C3MA=
github.com/BurntSushi/toml v0.3.2-0.20210621044154-20a94d639b8e/go.mod h1:t4zg8TkHfP16Vb3x4WKIw7zVYMit5QFtPEO8lOWxzTg=
github.com/BurntSushi/toml v0.3.2-0.20210624061728-01bfc69d1057/go.mod h1:NMj2lD5LfMqcE0w8tnqOsH6944oaqpI1974lrIwerfE=
github.com/BurntSushi/toml v0.3.2-0.20210704081116-ccff24ee4463/go.mod h1:EkRrMiQQmfxK6kIldz3QbPlhmVkrjW1RDJUnbDqGYvc=
github.com/BurntSushi/toml v0.4.0 h1:qD/r9AL67srjW6O3fcSKZDsXqzBNX6ieSRywr2hRrdE=
github.com/BurntSushi/toml v0.4.0/go.mod h1:wtejDu7Q0FhCWAo2aXkywSJyYFg01EDTKozLNCz2JBA=
github.com/BurntSushi/toml-test v0.1.1-0.20210620192437-de01089bbf76/go.mod h1:P/PrhmZ37t5llHfDuiouWXtFgqOoQ12SAh9j6EjrBR4=
github.com/BurntSushi/toml-test v0.1.1-0.20210624055653-1f6389604dc6/go.mod h1:UAIt+Eo8itMZAAgImXkPGDMYsT1SsJkVdB5TuONl86A=
github.com/BurntSushi/toml-test v0.1.1-0.20210704062846-269931e74e3f/go.mod h1:fnFWrIwqgHsEjVsW3RYCJmDo86oq9eiJ9u6bnqhtm2g=
github.com/BurntSushi/toml-test v0.1.1-0.20210723065233-facb9eccd4da h1:2QGUaQtV2u8V1USTI883wo+uxtZFAiZ4TCNupHJ98IU=
github.com/BurntSushi/toml-test v0.1.1-0.20210723065233-facb9eccd4da/go.mod h1:ve9Q/RRu2vHi42LocPLNvagxuUJh993/95b18bw/Nws=
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e h1:hHg27A0RSSp2Om9lubZpiMgVbvn39bsUmW9U5h0twqc=
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/klauspost/compress v1.13.3 h1:BtAvtV1+h0YwSVwWoYXMREPpYu9VzTJ9QDI1TEg/iQQ=
github.com/klauspost/compress v1.13.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
zgo.at/zli v0.0.0-20210619044753-e7020a328e59/go.mod h1:HLAc12TjNGT+VRXr76JnsNE3pbooQtwKWhX+RlDjQ2Y=

145
main.go
View File

@@ -1,11 +1,13 @@
// Copyright 2021 Clayton Craft <clayton@craftyguy.net>
// SPDX-License-Identifier: GPL-3.0-or-later
package main
import (
"bufio"
"debug/elf"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
@@ -13,10 +15,10 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"time"
"git.sr.ht/~sircmpwn/getopt"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/pkgs/archive"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/pkgs/deviceinfo"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/pkgs/misc"
@@ -28,21 +30,22 @@ func timeFunc(start time.Time, name string) {
}
func main() {
devinfo, err := deviceinfo.ReadDeviceinfo()
if err != nil {
deviceinfoFile := "/etc/deviceinfo"
if !exists(deviceinfoFile) {
log.Print("NOTE: deviceinfo (from device package) not installed yet, " +
"not building the initramfs now (it should get built later " +
"automatically.)")
os.Exit(0)
return
}
var outDir string
getopt.StringVar(&outDir, "d", "/boot", "Directory to output initfs(-extra) and other boot files, default: /boot")
if err := getopt.Parse(); err != nil {
devinfo, err := deviceinfo.ReadDeviceinfo(deviceinfoFile)
if err != nil {
log.Fatal(err)
}
outDir := flag.String("d", "/boot", "Directory to output initfs(-extra) and other boot files")
flag.Parse()
defer timeFunc(time.Now(), "mkinitfs")
kernVer, err := getKernelVersion()
@@ -50,10 +53,6 @@ func main() {
log.Fatal(err)
}
if err != nil {
log.Fatal(err)
}
// temporary working dir
workDir, err := ioutil.TempDir("", "mkinitfs")
if err != nil {
@@ -62,19 +61,19 @@ func main() {
defer os.RemoveAll(workDir)
log.Print("Generating for kernel version: ", kernVer)
log.Print("Output directory: ", outDir)
log.Print("Output directory: ", *outDir)
if err := generateInitfs("initramfs", workDir, kernVer, devinfo); err != nil {
log.Fatal(err)
log.Fatal("generateInitfs: ", err)
}
if err := generateInitfsExtra("initramfs-extra", workDir, devinfo); err != nil {
log.Fatal(err)
log.Fatal("generateInitfsExtra: ", err)
}
// Final processing of initramfs / kernel is done by boot-deploy
if err := bootDeploy(workDir, outDir); err != nil {
log.Fatal(err)
if err := bootDeploy(workDir, *outDir); err != nil {
log.Fatal("bootDeploy: ", err)
}
}
@@ -87,18 +86,29 @@ func bootDeploy(workDir string, outDir string) error {
if len(kernels) == 0 {
return errors.New("Unable to find any kernels at " + filepath.Join(outDir, "vmlinuz*"))
}
kernFile, err := os.Open(kernels[0])
// Pick a kernel that does not have suffixes added by boot-deploy
var kernFile string
for _, f := range kernels {
if strings.HasSuffix(f, "-dtb") || strings.HasSuffix(f, "-mtk") {
continue
}
kernFile = f
break
}
kernFd, err := os.Open(kernFile)
if err != nil {
return err
}
defer kernFile.Close()
defer kernFd.Close()
kernFileCopy, err := os.Create(filepath.Join(workDir, "vmlinuz"))
if err != nil {
return err
}
if _, err = io.Copy(kernFileCopy, kernFile); err != nil {
if _, err = io.Copy(kernFileCopy, kernFd); err != nil {
return err
}
kernFileCopy.Close()
@@ -111,33 +121,19 @@ func bootDeploy(workDir string, outDir string) error {
"-o", outDir,
"initramfs-extra")
if !exists(cmd.Path) {
return errors.New("boot-deploy command not found.")
return errors.New("boot-deploy command not found")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// err is ignored, since shellcheck will return != 0 if there are issues
if err := cmd.Run(); err != nil {
log.Print("'boot-deploy' command failed: ")
log.Print("'boot-deploy' command failed")
return err
}
return nil
}
func createInitfsRootDirs(initfsRoot string) {
dirs := []string{
"/bin", "/sbin", "/usr/bin", "/usr/lib", "/usr/sbin", "/proc", "/sys",
"/dev", "/tmp", "/lib", "/boot", "/sysroot", "/etc",
}
for _, dir := range dirs {
if err := os.MkdirAll(filepath.Join(initfsRoot, dir), os.FileMode(0775)); err != nil {
log.Fatal(err)
}
}
}
func exists(file string) bool {
if _, err := os.Stat(file); err == nil {
return true
@@ -359,13 +355,13 @@ func getFdeFiles(files misc.StringSet, devinfo deviceinfo.DeviceInfo) error {
}
// mesa hw accel
if devinfo.Deviceinfo_mesa_driver != "" {
if devinfo.MesaDriver != "" {
mesaFiles := misc.StringSet{
"/usr/lib/libEGL.so.1": false,
"/usr/lib/libGLESv2.so.2": false,
"/usr/lib/libgbm.so.1": false,
"/usr/lib/libudev.so.1": false,
"/usr/lib/xorg/modules/dri/" + devinfo.Deviceinfo_mesa_driver + "_dri.so": false,
"/usr/lib/xorg/modules/dri/" + devinfo.MesaDriver + "_dri.so": false,
}
if err := getFiles(files, mesaFiles, true); err != nil {
return err
@@ -418,6 +414,7 @@ func getInitfsFiles(files misc.StringSet, devinfo deviceinfo.DeviceInfo) error {
"/usr/sbin/telnetd": false,
"/sbin/kpartx": false,
"/etc/deviceinfo": false,
"/usr/bin/unudhcpd": false,
}
// Hook files & scripts
@@ -476,21 +473,19 @@ func getInitfsModules(files misc.StringSet, devinfo deviceinfo.DeviceInfo, kerne
return err
}
}
continue
} else if dir == "" {
// item is a module name
if err := getModule(files, file, modDir); err != nil {
log.Print("Unable to get module: ", file)
return err
}
continue
} else {
log.Printf("Unknown module entry: %q", item)
}
}
// deviceinfo modules
for _, module := range strings.Fields(devinfo.Deviceinfo_modules_initfs) {
for _, module := range strings.Fields(devinfo.ModulesInitfs) {
if err := getModule(files, module, modDir); err != nil {
log.Print("Unable to get modules from deviceinfo")
return err
@@ -522,7 +517,7 @@ func getKernelReleaseFile() (string, error) {
files, _ := filepath.Glob("/usr/share/kernel/*/kernel.release")
// only one kernel flavor supported
if len(files) != 1 {
return "", errors.New(fmt.Sprintf("Only one kernel release/flavor is supported, found: %q", files))
return "", fmt.Errorf("only one kernel release/flavor is supported, found: %q", files)
}
return files[0], nil
@@ -612,13 +607,7 @@ func generateInitfsExtra(name string, path string, devinfo deviceinfo.DeviceInfo
}
func stripExts(file string) string {
for {
if filepath.Ext(file) == "" {
break
}
file = strings.TrimSuffix(file, filepath.Ext(file))
}
return file
return strings.Split(file, ".")[0]
}
func getModulesInDir(files misc.StringSet, modPath string) error {
@@ -645,22 +634,21 @@ func getModulesInDir(files misc.StringSet, modPath string) error {
// anywhere
func getModule(files misc.StringSet, modName string, modDir string) error {
deps, err := getModuleDeps(modName, modDir)
if err != nil {
return err
modDep := filepath.Join(modDir, "modules.dep")
if !exists(modDep) {
log.Fatal("Kernel module.dep not found: ", modDir)
}
if len(deps) == 0 {
// retry and swap - and _ in module name
if strings.Contains(modName, "-") {
modName = strings.ReplaceAll(modName, "-", "_")
} else {
modName = strings.ReplaceAll(modName, "_", "-")
}
deps, err = getModuleDeps(modName, modDir)
if err != nil {
return err
}
fd, err := os.Open(modDep)
if err != nil {
log.Print("Unable to open modules.dep: ", modDep)
return err
}
defer fd.Close()
deps, err := getModuleDeps(modName, fd)
if err != nil {
return err
}
for _, dep := range deps {
@@ -675,30 +663,27 @@ func getModule(files misc.StringSet, modName string, modDir string) error {
return err
}
func getModuleDeps(modName string, modDir string) ([]string, error) {
// Get the canonicalized name for the module as represented in the given modules.dep io.reader
func getModuleDeps(modName string, modulesDep io.Reader) ([]string, error) {
var deps []string
modDep := filepath.Join(modDir, "modules.dep")
if !exists(modDep) {
log.Fatal("Kernel module.dep not found: ", modDir)
}
// split the module name on - and/or _, build a regex for matching
splitRe := regexp.MustCompile("[-_]+")
modNameReStr := splitRe.ReplaceAllString(modName, "[-_]+")
re := regexp.MustCompile("^" + modNameReStr + "$")
fd, err := os.Open(modDep)
if err != nil {
log.Print("Unable to open modules.dep: ", modDep)
return deps, err
}
defer fd.Close()
s := bufio.NewScanner(fd)
s := bufio.NewScanner(modulesDep)
for s.Scan() {
fields := strings.Fields(s.Text())
fields[0] = strings.TrimSuffix(fields[0], ":")
if modName != filepath.Base(stripExts(fields[0])) {
if len(fields) == 0 {
continue
}
for _, modPath := range fields {
deps = append(deps, modPath)
fields[0] = strings.TrimSuffix(fields[0], ":")
found := re.FindAll([]byte(filepath.Base(stripExts(fields[0]))), -1)
if len(found) > 0 {
deps = append(deps, fields...)
break
}
}
if err := s.Err(); err != nil {

View File

@@ -1,8 +1,10 @@
// Copyright 2021 Clayton Craft <clayton@craftyguy.net>
// SPDX-License-Identifier: GPL-3.0-or-later
package main
import (
"strings"
"testing"
)
@@ -24,3 +26,57 @@ func TestStripExts(t *testing.T) {
}
}
}
func stringSlicesEqual(a []string, b []string) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
var testModuleDep string = `
kernel/sound/soc/codecs/snd-soc-msm8916-digital.ko:
kernel/net/sched/act_ipt.ko.xz: kernel/net/netfilter/x_tables.ko.xz
kernel/drivers/watchdog/watchdog.ko.xz:
kernel/drivers/usb/serial/ir-usb.ko.xz: kernel/drivers/usb/serial/usbserial.ko.xz
kernel/drivers/gpu/drm/scheduler/gpu-sched.ko.xz:
kernel/drivers/hid/hid-alps.ko.xz:
kernel/net/netfilter/xt_u32.ko.xz: kernel/net/netfilter/x_tables.ko.xz
kernel/net/netfilter/xt_sctp.ko.xz: kernel/net/netfilter/x_tables.ko.xz
kernel/drivers/hwmon/gl518sm.ko.xz:
kernel/drivers/watchdog/dw_wdt.ko.xz: kernel/drivers/watchdog/watchdog.ko.xz
kernel/net/bluetooth/hidp/hidp.ko.xz: kernel/net/bluetooth/bluetooth.ko.xz kernel/net/rfkill/rfkill.ko.xz kernel/crypto/ecdh_generic.ko.xz kernel/crypto/ecc.ko.xz
kernel/fs/nls/nls_iso8859-1.ko.xz:
kernel/net/vmw_vsock/vmw_vsock_virtio_transport.ko.xz: kernel/net/vmw_vsock/vmw_vsock_virtio_transport_common.ko.xz kernel/drivers/virtio/virtio.ko.xz kernel/drivers/virtio/virtio_ring.ko.xz kernel/net/vmw_vsock/vsock.ko.xz
kernel/drivers/gpu/drm/panfrost/panfrost.ko.xz: kernel/drivers/gpu/drm/scheduler/gpu-sched.ko.xz
kernel/drivers/gpu/drm/msm/msm.ko: kernel/drivers/gpu/drm/drm_kms_helper.ko
`
func TestGetModuleDeps(t *testing.T) {
tables := []struct {
in string
expected []string
}{
{"nls-iso8859-1", []string{"kernel/fs/nls/nls_iso8859-1.ko.xz"}},
{"gpu_sched", []string{"kernel/drivers/gpu/drm/scheduler/gpu-sched.ko.xz"}},
{"dw-wdt", []string{"kernel/drivers/watchdog/dw_wdt.ko.xz",
"kernel/drivers/watchdog/watchdog.ko.xz"}},
{"gl518sm", []string{"kernel/drivers/hwmon/gl518sm.ko.xz"}},
{"msm", []string{"kernel/drivers/gpu/drm/msm/msm.ko",
"kernel/drivers/gpu/drm/drm_kms_helper.ko"}},
}
for _, table := range tables {
out, err := getModuleDeps(table.in, strings.NewReader(testModuleDep))
if err != nil {
t.Errorf("unexpected error with input: %q, error: %q", table.expected, err)
}
if !stringSlicesEqual(out, table.expected) {
t.Errorf("Expected: %q, got: %q", table.expected, out)
}
}
}

View File

@@ -1,19 +1,17 @@
// Copyright 2021 Clayton Craft <clayton@craftyguy.net>
// SPDX-License-Identifier: GPL-3.0-or-later
package archive
import (
"bytes"
"compress/flate"
"crypto/sha256"
"encoding/hex"
"github.com/cavaliercoder/go-cpio"
"github.com/klauspost/pgzip"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/pkgs/misc"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
@@ -52,12 +50,6 @@ func (archive *Archive) Write(path string, mode os.FileMode) error {
return err
}
// test the archive to make sure it's valid
if err := test(path); err != nil {
log.Print("Verification of archive failed!")
return err
}
if err := os.Chmod(path, mode); err != nil {
return err
}
@@ -65,38 +57,6 @@ func (archive *Archive) Write(path string, mode os.FileMode) error {
return nil
}
func checksum(path string) (string, error) {
var sum string
buf := make([]byte, 64*1024)
sha256 := sha256.New()
fd, err := os.Open(path)
defer fd.Close()
if err != nil {
log.Print("Unable to checksum: ", path)
return sum, err
}
// Read file in chunks
for {
bytes, err := fd.Read(buf)
if bytes > 0 {
_, err := sha256.Write(buf[:bytes])
if err != nil {
log.Print("Unable to checksum: ", path)
return sum, err
}
}
if err == io.EOF {
break
}
}
sum = hex.EncodeToString(sha256.Sum(nil))
return sum, nil
}
func (archive *Archive) AddFile(file string, dest string) error {
if err := archive.addDir(filepath.Dir(dest)); err != nil {
return err
@@ -144,6 +104,9 @@ func (archive *Archive) AddFile(file string, dest string) error {
// make sure target is an absolute path
if !filepath.IsAbs(target) {
target, err = misc.RelativeSymlinkTargetToDir(target, filepath.Dir(file))
if err != nil {
return err
}
}
// TODO: add verbose mode, print stuff like this:
// log.Printf("symlink: %q, target: %q", file, target)
@@ -180,19 +143,6 @@ func (archive *Archive) AddFile(file string, dest string) error {
return nil
}
// Use busybox gzip to test archive
func test(path string) error {
cmd := exec.Command("busybox", "gzip", "-t", path)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Print("'boot-deploy' command failed: ")
return err
}
return nil
}
func (archive *Archive) writeCompressed(path string, mode os.FileMode) error {
// TODO: support other compression formats, based on deviceinfo
fd, err := os.Create(path)

View File

@@ -1,53 +1,126 @@
// Copyright 2021 Clayton Craft <clayton@craftyguy.net>
// SPDX-License-Identifier: GPL-3.0-or-later
package deviceinfo
import (
"errors"
"github.com/BurntSushi/toml"
"bufio"
"fmt"
"io"
"log"
"os"
"reflect"
"strings"
)
// Note: fields must be exported (start with capital letter)
// https://github.com/BurntSushi/toml/issues/121
type DeviceInfo struct {
Deviceinfo_append_dtb string
Deviceinfo_arch string
Deviceinfo_bootimg_append_seandroidenforce string
Deviceinfo_bootimg_blobpack string
Deviceinfo_bootimg_dtb_second string
Deviceinfo_bootimg_mtk_mkimage string
Deviceinfo_bootimg_pxa string
Deviceinfo_bootimg_qcdt string
Deviceinfo_dtb string
Deviceinfo_flash_offset_base string
Deviceinfo_flash_offset_kernel string
Deviceinfo_flash_offset_ramdisk string
Deviceinfo_flash_offset_second string
Deviceinfo_flash_offset_tags string
Deviceinfo_flash_pagesize string
Deviceinfo_generate_bootimg string
Deviceinfo_generate_legacy_uboot_initfs string
Deviceinfo_mesa_driver string
Deviceinfo_mkinitfs_postprocess string
Deviceinfo_initfs_compression string
Deviceinfo_kernel_cmdline string
Deviceinfo_legacy_uboot_load_address string
Deviceinfo_modules_initfs string
Deviceinfo_flash_kernel_on_update string
AppendDtb string
Arch string
BootimgAppendSEAndroidEnforce string
BootimgBlobpack string
BootimgDtbSecond string
BootimgMtkMkimage string
BootimgPxa string
BootimgQcdt string
Dtb string
FlashKernelOnUpdate string
FlashOffsetBase string
FlashOffsetKernel string
FlashOffsetRamdisk string
FlashOffsetSecond string
FlashOffsetTags string
FlashPagesize string
GenerateBootimg string
GenerateLegacyUbootInitfs string
InitfsCompression string
KernelCmdline string
LegacyUbootLoadAddress string
MesaDriver string
MkinitfsPostprocess string
ModulesInitfs string
}
func ReadDeviceinfo() (DeviceInfo, error) {
file := "/etc/deviceinfo"
func ReadDeviceinfo(file string) (DeviceInfo, error) {
var deviceinfo DeviceInfo
_, err := os.Stat(file)
fd, err := os.Open(file)
if err != nil {
return deviceinfo, errors.New("Unable to find deviceinfo: " + file)
}
if _, err := toml.DecodeFile(file, &deviceinfo); err != nil {
return deviceinfo, err
}
defer fd.Close()
if err := unmarshal(fd, &deviceinfo); err != nil {
return deviceinfo, err
}
return deviceinfo, nil
}
// Unmarshals a deviceinfo into a DeviceInfo struct
func unmarshal(r io.Reader, devinfo *DeviceInfo) error {
s := bufio.NewScanner(r)
for s.Scan() {
line := s.Text()
if strings.HasPrefix(line, "#") {
continue
}
// line isn't setting anything, so just ignore it
if !strings.Contains(line, "=") {
continue
}
// sometimes line has a comment at the end after setting an option
line = strings.SplitN(line, "#", 2)[0]
line = strings.TrimSpace(line)
// must support having '=' in the value (e.g. kernel cmdline)
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("error parsing deviceinfo line, invalid format: %s", line)
}
name, val := parts[0], parts[1]
val = strings.ReplaceAll(val, "\"", "")
if name == "deviceinfo_format_version" && val != "0" {
return fmt.Errorf("deviceinfo format version %q is not supported", val)
}
fieldName := nameToField(name)
if fieldName == "" {
return fmt.Errorf("error parsing deviceinfo line, invalid format: %s", line)
}
field := reflect.ValueOf(devinfo).Elem().FieldByName(fieldName)
if !field.IsValid() {
// an option that meets the deviceinfo "specification", but isn't
// one we care about in this module
continue
}
field.SetString(val)
}
if err := s.Err(); err != nil {
log.Print("unable to parse deviceinfo: ", err)
return err
}
return nil
}
// Convert string into the string format used for DeviceInfo fields.
// Note: does not test that the resulting field name is a valid field in the
// DeviceInfo struct!
func nameToField(name string) string {
var field string
parts := strings.Split(name, "_")
for _, p := range parts {
if p == "deviceinfo" {
continue
}
field = field + strings.Title(p)
}
return field
}

View File

@@ -0,0 +1,81 @@
// Copyright 2021 Clayton Craft <clayton@craftyguy.net>
// SPDX-License-Identifier: GPL-3.0-or-later
package deviceinfo
import (
"fmt"
"reflect"
"strings"
"testing"
)
// Test conversion of name to DeviceInfo struct field format
func TestNameToField(t *testing.T) {
tables := []struct {
in string
expected string
}{
{"deviceinfo_dtb", "Dtb"},
{"dtb", "Dtb"},
{"deviceinfo_modules_initfs", "ModulesInitfs"},
{"modules_initfs", "ModulesInitfs"},
{"deviceinfo_modules_initfs___", "ModulesInitfs"},
}
for _, table := range tables {
out := nameToField(table.in)
if out != table.expected {
t.Errorf("expected: %q, got: %q", table.expected, out)
}
}
}
// Test unmarshalling with lines in deviceinfo
func TestUnmarshal(t *testing.T) {
tables := []struct {
// field is just used for reflection within the test, so it must be a
// valid DeviceInfo field
field string
in string
expected string
}{
{"ModulesInitfs", "deviceinfo_modules_initfs=\"panfrost foo bar bazz\"\n", "panfrost foo bar bazz"},
{"ModulesInitfs", "deviceinfo_modules_initfs=\"panfrost foo bar bazz\"", "panfrost foo bar bazz"},
// line with multiple '='
{"KernelCmdline",
"deviceinfo_kernel_cmdline=\"PMOS_NO_OUTPUT_REDIRECT fw_devlink=off nvme_core.default_ps_max_latency_us=5500 pcie_aspm.policy=performance\"\n",
"PMOS_NO_OUTPUT_REDIRECT fw_devlink=off nvme_core.default_ps_max_latency_us=5500 pcie_aspm.policy=performance"},
// empty option
{"ModulesInitfs", "deviceinfo_modules_initfs=\"\"\n", ""},
{"Dtb", "deviceinfo_dtb=\"freescale/imx8mq-librem5-r2 freescale/imx8mq-librem5-r3 freescale/imx8mq-librem5-r4\"\n",
"freescale/imx8mq-librem5-r2 freescale/imx8mq-librem5-r3 freescale/imx8mq-librem5-r4"},
// valid deviceinfo line, just not used in this module
{"", "deviceinfo_codename=\"pine64-pinebookpro\"", ""},
// line with comment at the end
{"MesaDriver", "deviceinfo_mesa_driver=\"panfrost\" # this is a nice driver", "panfrost"},
{"", "# this is a comment!\n", ""},
// empty lines are fine
{"", "", ""},
// line with whitepace characters only
{"", " \t \n\r", ""},
}
var d DeviceInfo
for _, table := range tables {
testName := fmt.Sprintf("unmarshal::'%s':", strings.ReplaceAll(table.in, "\n", "\\n"))
if err := unmarshal(strings.NewReader(table.in), &d); err != nil {
t.Errorf("%s received an unexpected err: ", err)
}
// Check against expected value
field := reflect.ValueOf(&d).Elem().FieldByName(table.field)
out := ""
if table.field != "" {
out = field.String()
}
if out != table.expected {
t.Errorf("%s expected: %q, got: %q", testName, table.expected, out)
}
}
}

View File

@@ -1,5 +1,6 @@
// Copyright 2021 Clayton Craft <clayton@craftyguy.net>
// SPDX-License-Identifier: GPL-3.0-or-later
package misc
import (