remove old unused code

This commit is contained in:
HikariKnight 2024-01-01 12:55:26 +01:00
parent 675083fb19
commit bd8f67decc
7 changed files with 0 additions and 886 deletions

View file

@ -21,13 +21,4 @@ func Tui() {
// New WIP Tui // New WIP Tui
pages.Welcome() pages.Welcome()
/*
// Make a blank model to keep our state in
m := NewModel()
// Start the program with the model
p := tea.NewProgram(m, tea.WithAltScreen())
_, err = p.Run()
errorcheck.ErrorCheck(err, "Failed to initialize UI")
*/
} }

View file

@ -1,126 +0,0 @@
package internal
import (
"encoding/base64"
"fmt"
"github.com/HikariKnight/quickpassthrough/internal/logger"
"github.com/HikariKnight/quickpassthrough/pkg/command"
tea "github.com/charmbracelet/bubbletea"
)
func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
// If we are not done
if m.focused != INSTALL && m.focused != DONE {
// Setup keybindings
switch msg.String() {
case "ctrl+c", "q":
// Exit when user presses Q or CTRL+C
return m, tea.Quit
case "enter":
if m.width != 0 {
// Process the selected item, if the return value is true then exit alt screen
if !m.processSelection() {
return m, tea.ExitAltScreen
}
}
case "ctrl+z", "backspace":
// Go backwards in the model
if m.focused > 0 && m.focused != DONE {
m.focused--
return m, nil
} else {
// If we are at the beginning, just exit
return m, tea.Quit
}
}
} else {
// If we are done then handle keybindings a bit differently
// Setup keybindings for authDialog
switch msg.String() {
case "ctrl+z":
// Since we have no QuickEmu support, skip the usb controller configuration
m.focused = VIDEO
case "ctrl+c":
// Exit when user presses CTRL+C
return m, tea.Quit
case "enter":
// If we are on the INSTALL dialog
if m.focused == INSTALL && m.authDialog.Value() != "" {
// Write to logger
logger.Printf("Getting authentication token by elevating with sudo once")
// Elevate with sudo
command.Elevate(
base64.StdEncoding.EncodeToString(
[]byte(
m.authDialog.Value(),
),
),
)
// Write to logger
logger.Printf("Attempting to free hash from memory")
// Blank the password field
m.authDialog.SetValue("")
fmt.Println(titleStyle.Render("Working... Application frozen until done, check debug.log for progress"))
// Start installation and send the password to the command
m.install()
// Move to the DONE dialog
m.focused = DONE
// Exit the alt screen as the output on the done dialog needs to be scrollable
return m, tea.ClearScreen
} else {
// Quit the application if we are on a different view
return m, tea.Quit
}
}
// Issue an UI update
m.authDialog, cmd = m.authDialog.Update(msg)
return m, cmd
}
case tea.WindowSizeMsg:
if m.width == 0 {
// Initialize the static lists and make sure the content
// does not extend past the screen
m.initLists(msg.Width, msg.Height)
} else {
// Else we are loaded and will update the sizing on the fly
m.height = msg.Height
m.width = msg.Width
// TODO: Find a better way to resize widgets when word wrapping happens
// BUG: currently breaks the UI rendering if word wrapping happens in some cases...
views := len(m.lists)
if msg.Width > 83 {
for i := 0; i < views; i++ {
m.lists[i].SetSize(m.width-m.offsetx[i], m.height-m.offsety[i])
// Update the styles with the correct width
dialogStyle = dialogStyle.Width(m.width)
listStyle = listStyle.Width(m.width)
titleStyle = titleStyle.Width(m.width - 4)
choiceStyle = choiceStyle.Width(m.width)
}
}
}
}
// Run another update loop
m.lists[m.focused], cmd = m.lists[m.focused].Update(msg)
return m, cmd
}

View file

@ -1,257 +0,0 @@
package internal
import (
"fmt"
"os"
"regexp"
"strings"
"github.com/HikariKnight/ls-iommu/pkg/errorcheck"
"github.com/HikariKnight/quickpassthrough/internal/configs"
"github.com/HikariKnight/quickpassthrough/internal/logger"
"github.com/HikariKnight/quickpassthrough/pkg/command"
"github.com/HikariKnight/quickpassthrough/pkg/fileio"
"github.com/HikariKnight/quickpassthrough/pkg/uname"
)
// This function processes the enter event
func (m *model) processSelection() bool {
switch m.focused {
case GPUS:
// Gets the selected item
selectedItem := m.lists[m.focused].SelectedItem()
// Gets the IOMMU group of the selected item
iommu_group_regex := regexp.MustCompile(`(\d{1,3})`)
iommu_group := iommu_group_regex.FindString(selectedItem.(item).desc)
// Add the gpu group to our model (this is so we can grab the vbios details later)
m.gpu_group = iommu_group
// Get all the gpu devices and related devices (same device id or in the same group)
items := iommuList2ListItem(getIOMMU("-grr", "-i", m.gpu_group, "-F", "vendor:,prod_name,optional_revision:,device_id"))
// Add the devices to the list
m.lists[GPU_GROUP].SetItems(items)
// Change focus to next index
m.focused++
case GPU_GROUP:
// Get the config
config := configs.GetConfig()
// Get the vbios path
m.vbios_path = getIOMMU("-g", "-i", m.gpu_group, "--rom")[0]
// Generate the VBIOS dumper script once the user has selected a GPU
configs.GenerateVBIOSDumper(m.vbios_path)
// Get the device ids for the selected gpu using ls-iommu
m.gpu_IDs = getIOMMU("-gr", "-i", m.gpu_group, "--id")
// If the kernel_args file already exists
if fileio.FileExist(config.Path.CMDLINE) {
// Delete it as we will have to make a new one anyway
err := os.Remove(config.Path.CMDLINE)
errorcheck.ErrorCheck(err, fmt.Sprintf("Could not remove %s", config.Path.CMDLINE))
}
// Write initial kernel_arg file
configs.Set_Cmdline(m.gpu_IDs)
// Change focus to the next view
m.focused++
case USB:
// Gets the selected item
selectedItem := m.lists[m.focused].SelectedItem()
// Gets the IOMMU group of the selected item
iommu_group_regex := regexp.MustCompile(`(\d{1,3})`)
iommu_group := iommu_group_regex.FindString(selectedItem.(item).desc)
// Get the USB controllers in the selected iommu group
items := iommuList2ListItem(getIOMMU("-ur", "-i", iommu_group, "-F", "vendor:,prod_name,optional_revision:,device_id"))
// Add the items to the list
m.lists[USB_GROUP].SetItems(items)
// Change focus to next index
m.focused++
case USB_GROUP:
m.focused++
case VBIOS:
// This is just an OK Dialog
m.focused++
case VIDEO:
// This is a YESNO Dialog
// Gets the selected item
selectedItem := m.lists[m.focused].SelectedItem()
// Get our config struct
config := configs.GetConfig()
// If user selected yes then
if selectedItem.(item).title == "YES" {
// Add disable VFIO video to the config
configs.DisableVFIOVideo(1)
} else {
// Add disable VFIO video to the config
configs.DisableVFIOVideo(0)
}
// If we have files for modprobe
if fileio.FileExist(config.Path.MODPROBE) {
// Configure modprobe
configs.Set_Modprobe(m.gpu_IDs)
}
// If we have a folder for dracut
if fileio.FileExist(config.Path.DRACUT) {
// Configure dracut
configs.Set_Dracut()
}
// If we have a mkinitcpio.conf file
if fileio.FileExist(config.Path.MKINITCPIO) {
configs.Set_Mkinitcpio()
}
// Configure grub2 here as we can make the config without sudo
if config.Bootloader == "grub2" {
// Write to logger
logger.Printf("Configuring grub2 manually")
configs.Configure_Grub2()
}
// Go to the next view
//m.focused++
// Because we have no QuickEmu support yet, just skip USB Controller configuration
m.focused = INSTALL
return true
case INTRO:
// This is an OK Dialog
// Create the config folder and the files related to this system
configs.InitConfigs()
// Go to the next view
m.focused++
case DONE:
// Return true so that the application will exit nicely
return true
}
// Return false as we are not done
return false
}
// This function starts the install process
// It takes 1 auth string as variable
func (m *model) install() {
// Get the config
config := configs.GetConfig()
// Make a stringlist to keep the output to show the user
var output []string
// Based on the bootloader, setup the configuration
if config.Bootloader == "kernelstub" {
// Write to logger
logger.Printf("Configuring systemd-boot using kernelstub")
// Configure kernelstub
output = append(output, configs.Set_KernelStub())
} else if config.Bootloader == "grubby" {
// Write to logger
logger.Printf("Configuring bootloader using grubby")
// Configure kernelstub
output = append(output, configs.Set_Grubby())
} else if config.Bootloader == "grub2" {
// Write to logger
logger.Printf("Configuring grub2 manually")
grub_output, _ := configs.Set_Grub2()
output = append(output, grub_output...)
} else {
kernel_args := fileio.ReadFile(config.Path.CMDLINE)
logger.Printf("Unsupported bootloader, please add the below line to your bootloaders kernel arguments\n%s", kernel_args)
}
// A lot of linux systems support modprobe along with their own module system
// So copy the modprobe files if we have them
modprobeFile := fmt.Sprintf("%s/vfio.conf", config.Path.MODPROBE)
if fileio.FileExist(modprobeFile) {
// Copy initramfs-tools module to system
output = append(output, configs.CopyToSystem(modprobeFile, "/etc/modprobe.d/vfio.conf"))
}
// Copy the config files for the system we have
initramfsFile := fmt.Sprintf("%s/modules", config.Path.INITRAMFS)
dracutFile := fmt.Sprintf("%s/vfio.conf", config.Path.DRACUT)
if fileio.FileExist(initramfsFile) {
// Copy initramfs-tools module to system
output = append(output, configs.CopyToSystem(initramfsFile, "/etc/initramfs-tools/modules"))
// Copy the modules file to /etc/modules
output = append(output, configs.CopyToSystem(config.Path.ETCMODULES, "/etc/modules"))
// Write to logger
logger.Printf("Executing: sudo update-initramfs -u")
// Update initramfs
output = append(output, "Executed: sudo update-initramfs -u\nSee debug.log for detailed output")
cmd_out, cmd_err, _ := command.RunErr("sudo", "update-initramfs", "-u")
cmd_out = append(cmd_out, cmd_err...)
// Write to logger
logger.Printf(strings.Join(cmd_out, "\n"))
} else if fileio.FileExist(dracutFile) {
// Copy dracut config to /etc/dracut.conf.d/vfio
output = append(output, configs.CopyToSystem(dracutFile, "/etc/dracut.conf.d/vfio"))
// Get systeminfo
sysinfo := uname.New()
// Write to logger
logger.Printf("Executing: sudo dracut -f -v --kver %s", sysinfo.Release)
// Update initramfs
output = append(output, fmt.Sprintf("Executed: sudo dracut -f -v --kver %s\nSee debug.log for detailed output", sysinfo.Release))
cmd_out, cmd_err, _ := command.RunErr("sudo", "dracut", "-f", "-v", "--kver", sysinfo.Release)
cmd_out = append(cmd_out, cmd_err...)
// Write to logger
logger.Printf(strings.Join(cmd_out, "\n"))
} else if fileio.FileExist(config.Path.MKINITCPIO) {
// Copy dracut config to /etc/dracut.conf.d/vfio
output = append(output, configs.CopyToSystem(config.Path.MKINITCPIO, "/etc/mkinitcpio.conf"))
// Write to logger
logger.Printf("Executing: sudo mkinitcpio -P")
// Update initramfs
output = append(output, "Executed: sudo mkinitcpio -P\nSee debug.log for detailed output")
cmd_out, cmd_err, _ := command.RunErr("sudo", "mkinitcpio", "-P")
cmd_out = append(cmd_out, cmd_err...)
// Write to logger
logger.Printf(strings.Join(cmd_out, "\n"))
}
m.installOutput = output
m.focused++
}

View file

@ -1,168 +0,0 @@
package internal
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/HikariKnight/quickpassthrough/internal/configs"
"github.com/HikariKnight/quickpassthrough/pkg/fileio"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
func (m model) View() string {
if m.width != 0 {
title := ""
view := ""
switch m.focused {
case INTRO:
title = dialogStyle.Render(
fmt.Sprint(
titleStyle.MarginLeft(0).Render("Welcome to QuickPassthrough!"),
"\n\n",
"This script is meant to make it easier to setup GPU passthrough for\n",
"Qemu based systems. WITH DIFFERENT 2 GPUS ON THE HOST SYSTEM\n",
"However due to the complexity of GPU passthrough\n",
"This script assumes you know how to do (or have done) the following.\n\n",
"* You have already enabled IOMMU, VT-d, SVM and/or AMD-v\n inside your UEFI/BIOS advanced settings.\n",
"* Know how to edit your bootloader\n",
"* Have a bootloader timeout of at least 3 seconds to access the menu\n",
"* Enable & Configure kernel modules\n",
"* Have a backup/snapshot of your system in case the script causes your\n system to be unbootable\n\n",
"By continuing you accept that I am not liable if your system\n",
"becomes unbootable, as you will be asked to verify the files generated",
),
)
view = listStyle.Render(m.lists[m.focused].View())
case GPUS:
title = titleStyle.MarginLeft(2).Render(
"Select a GPU to check the IOMMU groups of",
)
view = listStyle.Render(m.lists[m.focused].View())
case GPU_GROUP:
title = titleStyle.Render(
fmt.Sprint(
"Press ENTER/RETURN to set up all these devices for passthrough.\n",
"This list should only contain items related to your GPU.",
),
)
view = listStyle.Render(m.lists[m.focused].View())
case USB:
title = titleStyle.Render(
"[OPTIONAL]: Select a USB Controller to check the IOMMU groups of",
)
view = listStyle.Render(m.lists[m.focused].View())
case USB_GROUP:
title = titleStyle.Render(
fmt.Sprint(
"Press ENTER/RETURN to set up all these devices for passthrough.\n",
"This list should only contain the USB controller you want to use.",
),
)
view = listStyle.Render(m.lists[m.focused].View())
case VBIOS:
// Get the program directory
exe, _ := os.Executable()
scriptdir := filepath.Dir(exe)
// If we are using go run use the working directory instead
if strings.Contains(scriptdir, "/tmp/go-build") {
scriptdir, _ = os.Getwd()
}
text := dialogStyle.Render(
fmt.Sprint(
"Based on your GPU selection, a vbios extraction script has been generated for your convenience.\n",
"Passing a VBIOS rom to the card used for passthrough is required for some cards, but not all.\n",
"Some cards also requires you to patch your VBIOS romfile, check online if this is neccessary for your card!\n",
"The VBIOS will be read from:\n",
fmt.Sprintf(
"%s\n\n",
m.vbios_path,
),
"The script to extract the vbios has to be run as sudo and without a displaymanager running for proper dumping!\n",
"\n",
"You can run the script with:\n",
fmt.Sprintf(
"%s/utils/dump_vbios.sh",
scriptdir,
),
),
)
title = fmt.Sprintf(text, m.vbios_path, scriptdir)
view = listStyle.Render(m.lists[m.focused].View())
case VIDEO:
title = dialogStyle.Render(
fmt.Sprint(
"Disabling video output in Linux for the card you want to use in a VM\n",
"will make it easier to successfully do the passthrough without issues.\n",
"\n",
"Do you want to force disable video output in linux on this card?",
),
)
view = listStyle.Render(m.lists[m.focused].View())
case INSTALL:
title = dialogStyle.Render(
fmt.Sprint(
"The configuration files have been generated and are\n",
"located inside the \"config\" folder\n",
"\n",
"* The \"kernel_args\" file contains kernel arguments that your bootloader needs\n",
"* The \"quickemu\" folder contains files that might be\n useable for quickemu in the future\n",
"* The files inside the \"etc\" folder must be copied to your system.\n",
" NOTE: Verify that these files are correctly formated/edited!\n",
"* Once all files have been copied, you need to update your bootloader and rebuild\n",
" your initramfs using the tools to do so by your system.\n",
"\n",
"This program can do this for you, however the program will have to\n",
"type your password to sudo using STDIN, to avoid using STDIN press CTRL+C\n",
"and copy the files, update your bootloader and rebuild your initramfs manually.\n",
"If you want to go back and change something, press CTRL+Z\n",
"\nNOTE: A backup of the original files from the first run can be found in the backup folder",
),
)
view = m.authDialog.View()
case WORKING:
title = titleStyle.Render("Applying configurations!")
view = ""
m.authDialog.Update(tea.KeyEnter)
tea.Batch()
case DONE:
title = titleStyle.Render("Applied configurations!")
view = dialogStyle.Render(fmt.Sprintf("%s\n\nPress Enter to Exit.", strings.Join(m.installOutput, "\n")))
// If the bootloader is unknown/unsupported
config := configs.GetConfig()
if config.Bootloader == "unknown" {
// Change the view to reflect that
view = dialogStyle.Render(fmt.Sprintf("%s\n\nI do not have a good way to reliably edit your bootloader!\nPlease add: %s\nTo your bootloaders kernel arguments.\nPress Enter to Exit.", strings.Join(m.installOutput, "\n"), fileio.ReadFile(config.Path.CMDLINE)))
}
}
//return listStyle.SetString(fmt.Sprintf("%s\n\n", title)).Render(m.lists[m.focused].View())
return lipgloss.JoinVertical(lipgloss.Left, fmt.Sprintf("%s\n%s\n", title, view))
} else {
return "Loading..."
}
}

View file

@ -1,185 +0,0 @@
package internal
import (
"fmt"
"os/user"
"github.com/HikariKnight/ls-iommu/pkg/errorcheck"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
)
// Make a status type
type status int
// List item struct
type item struct {
title, desc string
}
// Functions needed for item struct
func (i item) Title() string { return i.title }
func (i item) Description() string { return i.desc }
func (i item) FilterValue() string { return i.title }
// Main Model
type model struct {
fetched []bool
lists []list.Model
gpu_group string
gpu_IDs []string
vbios_path string
focused status
offsetx []int
offsety []int
width int
height int
authDialog textinput.Model
installOutput []string
}
// Consts used to navigate the main model
const (
INTRO status = iota
GPUS
GPU_GROUP
VBIOS
VIDEO
USB
USB_GROUP
INSTALL
WORKING
DONE
)
func NewModel() *model {
// Get the username
user, err := user.Current()
errorcheck.ErrorCheck(err, "Error getting username")
username := user.Username
// Create the auth input and focus it
authInput := textinput.New()
authInput.EchoMode = textinput.EchoPassword
authInput.Prompt = fmt.Sprintf("\n[sudo] password for %s: ", username)
authInput.Focus()
// Create a blank model and return it
return &model{
authDialog: authInput,
}
}
func (m model) Init() tea.Cmd {
return nil
}
func (m *model) initLists(width, height int) {
defaultList := list.New([]list.Item{}, list.NewDefaultDelegate(), 0, 10)
choiceList := list.New([]list.Item{}, choiceDelegate{}, 0, 7)
// Disable features we wont need
defaultList.SetShowTitle(false)
defaultList.SetFilteringEnabled(false)
defaultList.SetSize(m.width, m.height)
choiceList.SetShowTitle(false)
choiceList.SetFilteringEnabled(false)
// Add height and width to our model so we can use it later
m.width = width
m.height = height
m.lists = []list.Model{
choiceList,
defaultList,
defaultList,
choiceList,
choiceList,
defaultList,
defaultList,
choiceList,
choiceList,
choiceList,
}
// Configure offsets for sizing
m.offsetx = []int{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}
m.offsety = []int{
18, 2, 3, 13, 5, 2, 3, 12, 0, 0,
}
// Update the styles with the correct width
dialogStyle = dialogStyle.Width(m.width)
listStyle = listStyle.Width(m.width)
titleStyle = titleStyle.Width(m.width - 4)
choiceStyle = choiceStyle.Width(m.width)
// Make m.fetched and set all values to FALSE
m.fetched = []bool{}
for range m.lists {
m.fetched = append(m.fetched, false)
}
// Set INTRO to the focused view
m.focused = INTRO
// Init INTRO choices
items := []list.Item{
item{title: "CONTINUE"},
}
//m.lists[INTRO].SetHeight(5)
m.lists[INTRO].SetItems(items)
m.lists[INTRO].SetSize(m.width-m.offsetx[INTRO], m.height-m.offsety[INTRO])
// Init GPU list
items = iommuList2ListItem(getIOMMU("-g", "-F", "vendor:,prod_name,optional_revision:,device_id"))
m.lists[GPUS].SetItems(items)
m.lists[GPUS].SetSize(m.width-m.offsetx[GPUS], m.height-m.offsety[GPUS])
m.fetched[GPUS] = true
// Setup the initial GPU_GROUP list
// The content in this list is generated from the selected choice from the GPU view
m.lists[GPU_GROUP].SetSize(m.width-m.offsetx[GPU_GROUP], m.height-m.offsety[GPU_GROUP])
// Init USB Controller list
items = iommuList2ListItem(getIOMMU("-u", "-F", "vendor:,prod_name,optional_revision:,device_id"))
m.lists[USB].SetItems(items)
m.lists[USB].SetSize(m.width-m.offsetx[USB], m.height-m.offsety[USB])
m.fetched[USB] = true
// Setup the initial USB_GROUP list
// The content in this list is generated from the selected choice from the USB view
m.lists[USB_GROUP].SetSize(m.width-m.offsetx[USB_GROUP], m.height-m.offsety[USB_GROUP])
// Init VBIOS choices
items = []list.Item{
item{title: "OK"},
}
m.lists[VBIOS].SetItems(items)
m.lists[VBIOS].SetSize(m.width-m.offsetx[VBIOS], m.height-m.offsety[VBIOS])
// Init VIDEO disable choises
items = []list.Item{
item{title: "YES"},
item{title: "NO"},
}
m.lists[VIDEO].SetItems(items)
m.lists[VIDEO].SetSize(m.width-m.offsetx[VIDEO], m.height-m.offsety[VIDEO])
// Init DONE choises
items = []list.Item{
item{title: "WAITING"},
}
m.lists[WORKING].SetItems(items)
m.lists[WORKING].SetSize(m.width-m.offsetx[WORKING], m.height-m.offsety[WORKING])
// Init DONE choises
items = []list.Item{
item{title: "FINISH"},
}
m.lists[DONE].SetItems(items)
m.lists[DONE].SetSize(m.width-m.offsetx[DONE], m.height-m.offsety[DONE])
}

View file

@ -1,55 +0,0 @@
package internal
import (
"fmt"
"io"
"strings"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
var (
titleStyle = lipgloss.NewStyle().
Background(lipgloss.Color("#5F5FD7")).
Foreground(lipgloss.Color("#FFFFFF")).
PaddingLeft(2).PaddingRight(2)
helpStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color(241))
listStyle = lipgloss.NewStyle().
PaddingLeft(2).
PaddingRight(2)
choiceStyle = lipgloss.NewStyle().
PaddingLeft(4).
PaddingRight(4)
selectedChoiceStyle = lipgloss.NewStyle().
PaddingLeft(2).
Foreground(lipgloss.Color("170"))
dialogStyle = lipgloss.NewStyle().
PaddingLeft(2)
)
// Choice delegate (for our dialog boxes)
type choiceDelegate struct{}
func (d choiceDelegate) Height() int { return 1 }
func (d choiceDelegate) Spacing() int { return 0 }
func (d choiceDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d choiceDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
i, ok := listItem.(item)
if !ok {
return
}
str := i.title
fn := choiceStyle.Render
if index == m.Index() {
fn = func(s ...string) string {
return selectedChoiceStyle.Render("| " + strings.Join(s, " "))
}
}
fmt.Fprint(w, fn(str))
}

View file

@ -1,86 +0,0 @@
package internal
import (
"bufio"
"bytes"
"fmt"
"io"
"os/exec"
"regexp"
"strings"
"github.com/HikariKnight/ls-iommu/pkg/errorcheck"
"github.com/HikariKnight/quickpassthrough/internal/logger"
"github.com/charmbracelet/bubbles/list"
"github.com/klauspost/cpuid/v2"
)
func getIOMMU(args ...string) []string {
var stdout, stderr bytes.Buffer
// Write to logger
logger.Printf("Executing: utils/ls-iommu %s\n", strings.Join(args, " "))
// Configure the ls-iommu command
cmd := exec.Command("utils/ls-iommu", args...)
cmd.Stderr = &stderr
cmd.Stdout = &stdout
// Execute the command
err := cmd.Run()
// Generate the correct iommu string for the system
var iommu_args string
cpuinfo := cpuid.CPU
// Write the argument based on which cpu the user got
switch cpuinfo.VendorString {
case "AuthenticAMD":
iommu_args = "iommu=pt amd_iommu=on"
case "GenuineIntel":
iommu_args = "iommu=pt intel_iommu=on"
}
// If ls-iommu returns an error then IOMMU is disabled
errorcheck.ErrorCheck(err,
fmt.Sprintf(
"IOMMU disabled in either UEFI/BIOS or in bootloader!\n"+
"For your bootloader, make sure you have added the kernel arguments:\n"+
"%s",
iommu_args,
),
)
// Read the output
var items []string
output, _ := io.ReadAll(&stdout)
// Write to logger
logger.Printf("ls-iommu query returned\n%s", string(output))
// Parse the output line by line
scanner := bufio.NewScanner(strings.NewReader(string(output)))
for scanner.Scan() {
// Write the objects into the list
items = append(items, scanner.Text())
}
// Return our list of items
return items
}
func iommuList2ListItem(stringList []string) []list.Item {
// Make the []list.Item struct
items := []list.Item{}
deviceID := regexp.MustCompile(`\[[a-f0-9]{4}:[a-f0-9]{4}\]\s+`)
// Parse the output line by line
for _, v := range stringList {
// Get the current line and split by :
objects := strings.Split(v, ": ")
// Write the objects into the list
items = append(items, item{title: deviceID.ReplaceAllString(objects[2], ""), desc: fmt.Sprintf("%s: %s: DeviceID: %s", objects[0], objects[1], objects[3])})
}
// Return our list of items
return items
}