From 92c2ea4772070eda3635385836b68e3f97c653aa Mon Sep 17 00:00:00 2001 From: "kayos@tcp.direct" Date: Thu, 18 Jul 2024 00:54:08 -0700 Subject: [PATCH] Resolve https://github.com/HikariKnight/quickpassthrough/pull/28#discussion_r1646730751 --- internal/configs/config_bootloaders.go | 7 ++- internal/pages/06_finalize.go | 6 +-- pkg/command/command.go | 20 +++++---- pkg/command/command_test.go | 61 ++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 15 deletions(-) create mode 100644 pkg/command/command_test.go diff --git a/internal/configs/config_bootloaders.go b/internal/configs/config_bootloaders.go index 32287d8..281cc4d 100644 --- a/internal/configs/config_bootloaders.go +++ b/internal/configs/config_bootloaders.go @@ -82,9 +82,8 @@ func Set_KernelStub(isRoot bool) { kernel_args := fileio.ReadFile(config.Path.CMDLINE) // Run and log, check for errors - common.ErrorCheck(command.ExecAndLogSudo(isRoot, true, - "kernelstub -a "+fmt.Sprintf("\"%s\"", kernel_args), - ), + common.ErrorCheck( + command.ExecAndLogSudo(isRoot, true, "kernelstub", "-a", kernel_args), "Error, kernelstub command returned exit code 1", ) } @@ -98,7 +97,7 @@ func Set_Grubby(isRoot bool) string { kernel_args := fileio.ReadFile(config.Path.CMDLINE) // Run and log, check for errors - err := command.ExecAndLogSudo(isRoot, true, "grubby --update-kernel=ALL "+fmt.Sprintf("--args=%s", kernel_args)) + err := command.ExecAndLogSudo(isRoot, true, "grubby", "--update-kernel=ALL", fmt.Sprintf("--args=%s", kernel_args)) common.ErrorCheck(err, "Error, grubby command returned exit code 1") // Return what we did diff --git a/internal/pages/06_finalize.go b/internal/pages/06_finalize.go index 35260ec..a1ab656 100644 --- a/internal/pages/06_finalize.go +++ b/internal/pages/06_finalize.go @@ -201,7 +201,7 @@ func installPassthrough(config *configs.Config) { // Copy the modules file to /etc/modules configs.CopyToSystem(config.IsRoot, config.Path.ETCMODULES, "/etc/modules") - if err = command.ExecAndLogSudo(config.IsRoot, true, "update-initramfs -u"); err != nil { + if err = command.ExecAndLogSudo(config.IsRoot, true, "update-initramfs", "-u"); err != nil { log.Fatalf("Failed to update initramfs: %s", err) } @@ -212,7 +212,7 @@ func installPassthrough(config *configs.Config) { // Get systeminfo sysinfo := uname.New() - if err = command.ExecAndLogSudo(config.IsRoot, true, "dracut -f -v --kver "+sysinfo.Release); err != nil { + if err = command.ExecAndLogSudo(config.IsRoot, true, "dracut", "-f", "-v", "--kver", sysinfo.Release); err != nil { log.Fatalf("Failed to update initramfs: %s", err) } @@ -220,7 +220,7 @@ func installPassthrough(config *configs.Config) { // Copy dracut config to /etc/dracut.conf.d/vfio configs.CopyToSystem(config.IsRoot, config.Path.MKINITCPIO, "/etc/mkinitcpio.conf") - if err = command.ExecAndLogSudo(config.IsRoot, true, "mkinitcpio -P"); err != nil { + if err = command.ExecAndLogSudo(config.IsRoot, true, "mkinitcpio", "-P"); err != nil { log.Fatalf("Failed to update initramfs: %s", err) } } diff --git a/pkg/command/command.go b/pkg/command/command.go index 65702d5..e6ba915 100644 --- a/pkg/command/command.go +++ b/pkg/command/command.go @@ -120,17 +120,22 @@ func Clear() { // - noisy determines if we should print the command to the user // noisy isn't set to true by our copy caller, as it logs differently, // but other callers set it. -func ExecAndLogSudo(isRoot, noisy bool, cmd string) error { - if !isRoot && !strings.HasPrefix(cmd, "sudo") { - cmd = fmt.Sprintf("sudo %s", cmd) +func ExecAndLogSudo(isRoot, noisy bool, exe string, args ...string) error { + if !isRoot && exe != "sudo" { + og := exe + exe = "sudo" + newArgs := make([]string, 0) + newArgs = append(newArgs, og) + newArgs = append(newArgs, args...) + args = newArgs } // Write to logger - logger.Printf("Executing (elevated): %s\n", cmd) + logger.Printf("Executing (elevated): %s %s\n", exe, strings.Join(args, " ")) if noisy { // Print to the user - fmt.Printf("Executing (elevated): %s\nSee debug.log for detailed output\n", cmd) + fmt.Printf("Executing (elevated): %s %s\nSee debug.log for detailed output\n", exe, strings.Join(args, " ")) } wd, err := os.Getwd() @@ -138,8 +143,7 @@ func ExecAndLogSudo(isRoot, noisy bool, cmd string) error { return err } - cs := strings.Fields(cmd) - r := exec.Command(cs[0], cs[1:]...) + r := exec.Command(exe, args...) r.Dir = wd cmdCombinedOut, err := r.CombinedOutput() @@ -155,7 +159,7 @@ func ExecAndLogSudo(isRoot, noisy bool, cmd string) error { } if err != nil { - err = fmt.Errorf("failed to execute %s: %w\n%s", cmd, err, outStr) + err = fmt.Errorf("failed to execute %s: %w\n%s", exe, err, outStr) } return err diff --git a/pkg/command/command_test.go b/pkg/command/command_test.go new file mode 100644 index 0000000..f6fa119 --- /dev/null +++ b/pkg/command/command_test.go @@ -0,0 +1,61 @@ +package command + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +const fakeSudo = `#!/bin/sh +"$@" -qptest` + +const fakeUtil = `#!/bin/sh +echo "$@" +if [ "$4" = "-qptest" ]; then exit 0; else exit 1; fi` + +func setupExecTestEnv(t *testing.T) (string, string) { + t.Helper() + + tmpDir := t.TempDir() + fakeSudoPath := filepath.Join(tmpDir, "sudo") + fakeUtilPath := filepath.Join(tmpDir, "util") + + if err := os.WriteFile(fakeSudoPath, []byte(fakeSudo), 0755); err != nil { + t.Fatalf("failed to write fake sudo stub: %s", err.Error()) + } + if err := os.WriteFile(fakeUtilPath, []byte(fakeUtil), 0755); err != nil { + t.Fatalf("failed to write fake util stub: %s", err.Error()) + } + t.Setenv("PATH", tmpDir+":"+os.Getenv("PATH")) + + return fakeSudoPath, fakeUtilPath +} + +func TestExecAndLogSudo(t *testing.T) { + _, fakeUtilPath := setupExecTestEnv(t) + + args := []string{"i am a string with spaces", "i came to ruin parsers and chew bubble gum", "and I'm all out of bubblegum."} + + t.Run("is_not_root", func(t *testing.T) { + if err := ExecAndLogSudo(false, false, "util", args...); err != nil { + t.Errorf("unexpected error: %s", err.Error()) + } + }) + + t.Run("is_root", func(t *testing.T) { + newFakeUtil := strings.Replace(fakeUtil, "exit 1", "exit 0", 1) + newFakeUtil = strings.Replace(newFakeUtil, "exit 0", "exit 1", 1) + if err := os.WriteFile(fakeUtilPath, []byte(newFakeUtil), 0755); err != nil { + t.Fatalf("failed to overwrite fake util with modified stub: %s", err.Error()) + } + if err := ExecAndLogSudo(false, false, "util", args...); err == nil { + t.Errorf("expected error when using modified util with sudo, got nil") + } + + if err := ExecAndLogSudo(true, true, "util", args...); err != nil { + t.Errorf("unexpected error: %s", err.Error()) + } + }) + +}