Running autoport as root has the annoying side effect of making all generated files owned by root. Prevent this by using sudo to invoke log-making programs (lspci, dmidecode, acpidump, inteltool, ectool, superiotool). These programs either need to be run as root or allow collecting more information if run as root (lspci). In case there's a valid reason not to use sudo, provide a prompt to let autoport run the programs directly, as it originally did. There might be someone trying to run autoport from an OS that lacks sudo. Change-Id: I4bf4ddf8dd2cb930e9b7303e2ea986d8c072aa7a Signed-off-by: Angel Pons <th3fanbus@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/82404 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Nico Huber <nico.h@gmx.de>
		
			
				
	
	
		
			274 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"log"
 | |
| 	"os"
 | |
| 	"os/exec"
 | |
| 	"strings"
 | |
| 	"bytes"
 | |
| )
 | |
| 
 | |
| type LogMakingProgram struct {
 | |
| 	name string
 | |
| 	prefixes []string
 | |
| 	args []string
 | |
| }
 | |
| 
 | |
| func ExecCommand(sudo bool, name string, arg []string) *exec.Cmd {
 | |
| 	if sudo {
 | |
| 		return exec.Command("sudo", append([]string{name}, arg...)...)
 | |
| 	} else {
 | |
| 		return exec.Command(name, arg...)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (prog LogMakingProgram) TryRunAndSave(output string, sudo bool, prefix string) error {
 | |
| 	f, err := os.Create(output)
 | |
| 	if err != nil {
 | |
| 		log.Fatal(err)
 | |
| 	}
 | |
| 	defer f.Close()
 | |
| 
 | |
| 	cmd := ExecCommand(sudo, prefix+prog.name, prog.args)
 | |
| 	cmd.Stdout = f
 | |
| 	cmd.Stderr = f
 | |
| 
 | |
| 	err = cmd.Start()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return cmd.Wait()
 | |
| }
 | |
| 
 | |
| func (prog LogMakingProgram) RunAndSave(outDir string, sudo bool) {
 | |
| 	output := fmt.Sprintf("%s/%s.log", outDir, prog.name)
 | |
| 	cmdline := strings.Join(append([]string{prog.name}, prog.args...), " ")
 | |
| 
 | |
| 	fmt.Println("Running: "+cmdline)
 | |
| 
 | |
| 	var sb strings.Builder
 | |
| 	for _, prefix := range prog.prefixes {
 | |
| 		err := prog.TryRunAndSave(output, sudo, prefix)
 | |
| 		if err == nil {
 | |
| 			return
 | |
| 		}
 | |
| 		sb.WriteString("\nError running '"+prefix+cmdline+"': "+err.Error()+"\n")
 | |
| 		data, ferr := os.ReadFile(output)
 | |
| 		if ferr != nil {
 | |
| 			sb.WriteString("<failed to open log>\n")
 | |
| 		} else {
 | |
| 			if len(data) > 0 {
 | |
| 				sb.WriteString("Program output:\n\n")
 | |
| 				sb.WriteString(string(data))
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	fmt.Println("\nCould not run program: '"+cmdline+"'")
 | |
| 	log.Fatal(sb.String())
 | |
| }
 | |
| 
 | |
| const MAXPROMPTRETRY = 3
 | |
| 
 | |
| func PromptUser(prompt string, opts []string) (match string, err error) {
 | |
| 	for i := 1; i < MAXPROMPTRETRY; i++ {
 | |
| 		fmt.Printf("%s. (%s) Default:%s\n", prompt,
 | |
| 		           strings.Join(opts, "/"), opts[0])
 | |
| 		var usrInput string
 | |
| 		fmt.Scanln(&usrInput)
 | |
| 
 | |
| 		// Check for default entry
 | |
| 		if usrInput == "" {
 | |
| 			match = opts[0]
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		for _, opt := range opts {
 | |
| 			if opt == usrInput {
 | |
| 				match = opt
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	err = errors.New("max retries exceeded")
 | |
| 	fmt.Fprintln(os.Stderr, "ERROR: max retries exceeded")
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func AppendYesNo(yesFirst bool, yeah []string, nope []string) []string {
 | |
| 	if yesFirst {
 | |
| 		return append(yeah, nope...)
 | |
| 	} else {
 | |
| 		return append(nope, yeah...)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func PromptUserBool(prompt string, fallback bool) bool {
 | |
| 	yeah := []string{"y", "yes"}
 | |
| 	nope := []string{"n", "no"}
 | |
| 
 | |
| 	opt, err := PromptUser(prompt, AppendYesNo(fallback, yeah, nope))
 | |
| 	if err != nil {
 | |
| 		// Continue even if there is an error
 | |
| 		return fallback
 | |
| 	}
 | |
| 	for _, val := range yeah {
 | |
| 		if opt == val {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func MakeHDALogs(outDir string, cardName string) {
 | |
| 	SysDir := "/sys/class/sound/" + cardName + "/"
 | |
| 	files, _ := ioutil.ReadDir(SysDir)
 | |
| 	for _, f := range files {
 | |
| 		if (strings.HasPrefix(f.Name(), "hw") || strings.HasPrefix(f.Name(), "hdaudio")) && f.IsDir() {
 | |
| 			in, err := os.Open(SysDir + f.Name() + "/init_pin_configs")
 | |
| 			defer in.Close()
 | |
| 			if err != nil {
 | |
| 				log.Fatal(err)
 | |
| 			}
 | |
| 			out, err := os.Create(outDir + "/pin_" + strings.Replace(f.Name(), "hdaudio", "hw", -1))
 | |
| 			if err != nil {
 | |
| 				log.Fatal(err)
 | |
| 			}
 | |
| 			defer out.Close()
 | |
| 			io.Copy(out, in)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	ProcDir := "/proc/asound/" + cardName + "/"
 | |
| 	files, _ = ioutil.ReadDir(ProcDir)
 | |
| 	for _, f := range files {
 | |
| 		if strings.HasPrefix(f.Name(), "codec#") && !f.IsDir() {
 | |
| 			in, err := os.Open(ProcDir + f.Name())
 | |
| 			defer in.Close()
 | |
| 			if err != nil {
 | |
| 				log.Fatal(err)
 | |
| 			}
 | |
| 			out, err := os.Create(outDir + "/" + f.Name())
 | |
| 			if err != nil {
 | |
| 				log.Fatal(err)
 | |
| 			}
 | |
| 			defer out.Close()
 | |
| 			io.Copy(out, in)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func MakeLogs(outDir string) {
 | |
| 	os.MkdirAll(outDir, 0700)
 | |
| 
 | |
| 	sudo := PromptUserBool("Should autoport use sudo to run the commands to make the logs? "+
 | |
| 		"This is recommended over running autoport as root, since the generated files "+
 | |
| 		"won't be owned by root. If running as root already because sudo isn't available, "+
 | |
| 		"choose 'no'. Otherwise, run autoport as a regular (non-root) user and choose 'yes'.",
 | |
| 		true)
 | |
| 
 | |
| 	probeGFX := PromptUserBool("WARNING: Running inteltool MAY cause your system to hang when it attempts "+
 | |
| 		"to probe for graphics registers.  Having the graphics registers will help create a better port. "+
 | |
| 		"Should autoport probe these registers?",
 | |
| 		true)
 | |
| 
 | |
| 	inteltoolArgs := "-a"
 | |
| 	if probeGFX {
 | |
| 		inteltoolArgs += "f"
 | |
| 	}
 | |
| 
 | |
| 	var programs = []LogMakingProgram {
 | |
| 		LogMakingProgram {
 | |
| 			name: "lspci",
 | |
| 			prefixes: []string{""},
 | |
| 			args: []string{"-nnvvvxxxx"},
 | |
| 		},
 | |
| 		LogMakingProgram {
 | |
| 			name: "dmidecode",
 | |
| 			prefixes: []string{""},
 | |
| 			args: []string{},
 | |
| 		},
 | |
| 		LogMakingProgram {
 | |
| 			name: "acpidump",
 | |
| 			prefixes: []string{""},
 | |
| 			args: []string{},
 | |
| 		},
 | |
| 		LogMakingProgram {
 | |
| 			name: "inteltool",
 | |
| 			prefixes: []string{"../inteltool/", ""},
 | |
| 			args: []string{inteltoolArgs},
 | |
| 		},
 | |
| 		LogMakingProgram {
 | |
| 			name: "ectool",
 | |
| 			prefixes: []string{"../ectool/", ""},
 | |
| 			args: []string{"-pd"},
 | |
| 		},
 | |
| 		LogMakingProgram {
 | |
| 			name: "superiotool",
 | |
| 			prefixes: []string{"../superiotool/", ""},
 | |
| 			args: []string{"-ade"},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	fmt.Println("Making logs...")
 | |
| 	for _, prog := range programs {
 | |
| 		prog.RunAndSave(outDir, sudo)
 | |
| 	}
 | |
| 
 | |
| 	SysSound := "/sys/class/sound/"
 | |
| 	card := ""
 | |
| 	cards, _ := ioutil.ReadDir(SysSound)
 | |
| 	for _, f := range cards {
 | |
| 		if strings.HasPrefix(f.Name(), "card") {
 | |
| 			cid, err := ioutil.ReadFile(SysSound + f.Name() + "/id")
 | |
| 			if err == nil && bytes.Equal(cid, []byte("PCH\n")) {
 | |
| 				fmt.Fprintln(os.Stderr, "PCH sound card is", f.Name())
 | |
| 				card = f.Name()
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if card != "" {
 | |
| 		MakeHDALogs(outDir, card)
 | |
| 	} else {
 | |
| 		fmt.Fprintln(os.Stderr, "HDAudio not found on PCH.")
 | |
| 	}
 | |
| 
 | |
| 	for _, fname := range []string{"cpuinfo", "ioports"} {
 | |
| 		in, err := os.Open("/proc/" + fname)
 | |
| 		defer in.Close()
 | |
| 		if err != nil {
 | |
| 			log.Fatal(err)
 | |
| 		}
 | |
| 		out, err := os.Create(outDir + "/" + fname + ".log")
 | |
| 		if err != nil {
 | |
| 			log.Fatal(err)
 | |
| 		}
 | |
| 		defer out.Close()
 | |
| 		io.Copy(out, in)
 | |
| 	}
 | |
| 
 | |
| 	out, err := os.Create(outDir + "/input_bustypes.log")
 | |
| 	if err != nil {
 | |
| 		log.Fatal(err)
 | |
| 	}
 | |
| 	defer out.Close()
 | |
| 
 | |
| 	ClassInputDir := "/sys/class/input/"
 | |
| 	files, _ := ioutil.ReadDir(ClassInputDir)
 | |
| 	for _, f := range files {
 | |
| 		if strings.HasPrefix(f.Name(), "input") && !f.Mode().IsRegular() { /* Allow both dirs and symlinks.  */
 | |
| 			in, err := os.Open(ClassInputDir + f.Name() + "/id/bustype")
 | |
| 			defer in.Close()
 | |
| 			if err != nil {
 | |
| 				log.Fatal(err)
 | |
| 			}
 | |
| 			io.Copy(out, in)
 | |
| 		}
 | |
| 	}
 | |
| }
 |