Most stuff should work

pull/15/head
qaidvoid 4 years ago
parent 9df9a7ab8b
commit 03284e6ad7

@ -0,0 +1,20 @@
CXX := g++
CXX_FLAGS := -Wall -Wextra -std=c++17
BIN := bin
SRC := src
INCLUDE := include
EXECUTABLE := passthrough
all: $(EXECUTABLE)
run: clean all
clear
./$(EXECUTABLE)
$(EXECUTABLE): $(SRC)/*.cpp
$(CXX) $(CXX_FLAGS) -I$(INCLUDE) $^ -o $@
clean:
-rm passthrough

@ -1,5 +1,9 @@
## Automated Setup
#### ** TODO : NOT SURE **
#### Install required tools
```sh
sudo pacman -S qemu libvirt edk2-ovmf virt-manager dnsmasq ebtables iptables
```
## Manual Setup
<b>Note</b>: Replace win10 with your virtual machine's name on libvirt hooks and virsh commands.

@ -0,0 +1,11 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <memory>
#include <sysinfo.h>
#include <shell.h>
void check_vt_support();
bool check_iommu();
void enable_iommu();
void configure_iommu();

@ -0,0 +1,44 @@
#include <sys/stat.h>
#include <iostream>
#include <fstream>
#include <bits/stdc++.h>
#include <sysinfo.h>
void libvirt_hook();
void hook_begin();
void hook_release();
std::string begin_script();
std::string end_script();
inline const char *hooks_path = "/etc/libvirt/hooks";
inline const char *qemu_hook = "/etc/libvirt/hooks/qemu";
inline const char *vm_path = "/etc/libvirt/hooks/qemu.d/win10";
inline const char *vm_prepare = "/etc/libvirt/hooks/qemu.d/win10/prepare";
inline const char *vm_begin = "/etc/libvirt/hooks/qemu.d/win10/prepare/begin";
inline const char *begin_sh = "/etc/libvirt/hooks/qemu.d/win10/prepare/begin/begin.sh";
inline const char *vm_release = "/etc/libvirt/hooks/qemu.d/win10/release";
inline const char *vm_end = "/etc/libvirt/hooks/qemu.d/win10/release/end";
inline const char *end_sh = "/etc/libvirt/hooks/qemu.d/win10/release/end/end.sh";
inline const std::string qemu_script = R"#(#!/bin/bash
GUEST_NAME="$1"
HOOK_NAME="$2"
STATE_NAME="$3"
MISC="${@:4}"
BASEDIR="$(dirname $0)"
HOOKPATH="$BASEDIR/qemu.d/$GUEST_NAME/$HOOK_NAME/$STATE_NAME"
set -e # If a script exits with an error, we should as well.
if [ -f "$HOOKPATH" ]; then
eval \""$HOOKPATH"\" "$@"
elif [ -d "$HOOKPATH" ]; then
while read file; do
eval \""$file"\" "$@"
done <<< "$(find -L "$HOOKPATH" -maxdepth 1 -type f -executable -print;)"
fi
)#";

@ -0,0 +1,4 @@
#include <memory>
#include <iostream>
std::string shell_cmd(char const *cmd);

@ -0,0 +1,9 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <shell.h>
std::string get_cpu_vendor();
std::string get_gpu_vendor();
std::string get_vga_slot();
std::string get_audio_slot();

@ -0,0 +1,10 @@
#include <iostream>
#include <fstream>
#include <sys/stat.h>
#include <memory>
#include <shell.h>
void install_tools();
void enable_services();
void user_mod();
std::string get_init();

@ -0,0 +1,83 @@
#include <iommu.h>
void configure_iommu()
{
check_vt_support();
enable_iommu();
}
void check_vt_support()
{
std::cout << "\033[1;36mChecking system for virtualisation support \033[0m";
std::string res = shell_cmd("lscpu | grep Virtualization");
if (res.empty())
throw std::runtime_error("\n\033[1;31mVirtualisation is not enabled on your system!\033[0m");
std::cout << "\033[1;32m\u2714\033[0m" << std::endl;
}
bool check_iommu()
{
std::cout << "\033[1;36mIs IOMMU enabled? \033[0m";
std::string res = shell_cmd("(dmesg | grep 'IOMMU enabled') 2>&1");
if (res.find("IOMMU enabled") != std::string::npos)
std::cout << "\033[1;32m\u2714\033[0m" << std::endl;
else
{
std::cout << "\033[1;31m\u2718\033[0m" << std::endl;
return false;
}
return true;
}
void enable_iommu()
{
if (!check_iommu())
{
std::ifstream ifs("/etc/default/grub");
std::ofstream ofs("./tmp/grub");
if (ifs.fail())
throw std::runtime_error("\033[1;31mGrubloader doesn't exist or I can't find it on your system.\033[0m");
if (ofs.fail())
throw std::runtime_error("\033[1;31mFailed to create temporary file.\033[0m");
std::string line;
while (getline(ifs, line))
{
std::istringstream iss(line);
std::string key;
if (std::getline(iss, key, '=') && key.rfind("#", 0) != 0)
{
std::string value;
std::getline(iss, value);
if (key == "GRUB_CMDLINE_LINUX_DEFAULT")
{
if (get_cpu_vendor() == "intel")
{
if (value.find("intel_iommu=on") == std::string::npos)
value.insert(*value.cbegin(), " intel_iommu=on");
}
else if (value.find("amd_iommu=on") == std::string::npos)
value.insert(*value.cbegin(), " amd_iommu=on");
if (value.find("iommu=pt") == std::string::npos)
value.insert(*value.cbegin(), " iommu=pt");
}
ofs << key << "=" << value << '\n';
}
else
ofs << line << '\n';
}
ifs.close();
ofs.close();
std::string res = shell_cmd("(mv -f ./tmp/grub /etc/default/grub) 2>&1");
system("grub-mkconfig -o /boot/grub/grub.cfg");
if (res.empty())
throw std::runtime_error("\033[1;32mIOMMU enabled. Please reboot your system to continue.\033[0m");
else
throw std::runtime_error("\033[1;31mFailed to enable IOMMU.\n" + res + "\033[0m");
}
}

@ -0,0 +1,71 @@
#include <libvirt.h>
void libvirt_hook()
{
struct stat buf;
if (stat(hooks_path, &buf) != 0)
if (mkdir(hooks_path, 0755) == -1)
throw std::runtime_error(strerror(errno));
if (stat(qemu_hook, &buf) != 0)
{
std::ofstream file(qemu_hook);
file << qemu_script;
file.close();
if (chmod(qemu_hook, 0755) == -1)
throw std::runtime_error(strerror(errno));
}
}
void hook_begin()
{
struct stat buf;
if (stat(vm_path, &buf) != 0)
if (mkdir(vm_path, 0755) == -1)
throw std::runtime_error(strerror(errno));
if (stat(vm_prepare, &buf) != 0)
if (mkdir(vm_prepare, 0755) == -1)
throw std::runtime_error(strerror(errno));
if (stat(vm_begin, &buf) != 0)
if (mkdir(vm_begin, 0755) == -1)
throw std::runtime_error(strerror(errno));
if (stat(begin_sh, &buf) != 0)
{
std::ofstream file(begin_sh);
file << "#BEGIN";
file.close();
if (chmod(begin_sh, 0755) == -1)
throw std::runtime_error(strerror(errno));
}
}
void hook_release()
{
struct stat buf;
if (stat(vm_path, &buf) != 0)
if (mkdir(vm_path, 0755) == -1)
throw std::runtime_error(strerror(errno));
if (stat(vm_prepare, &buf) != 0)
if (mkdir(vm_prepare, 0755) == -1)
throw std::runtime_error(strerror(errno));
if (stat(vm_begin, &buf) != 0)
if (mkdir(vm_begin, 0755) == -1)
throw std::runtime_error(strerror(errno));
if (stat(end_sh, &buf) != 0)
{
std::ofstream file(end_sh);
file << "#END";
file.close();
if (chmod(end_sh, 0755) == -1)
throw std::runtime_error(strerror(errno));
}
}
std::string begin_script()
{
return "";
}
std::string end_script()
{
return "";
}

@ -0,0 +1,25 @@
#include <iommu.h>
#include <tools.h>
#include <libvirt.h>
int main()
{
try
{
char cnf;
configure_iommu();
std::cout << "Do you want to install required packages automatically? (y/n) ";
std::cin >> cnf;
if (tolower(cnf) == 'y')
install_tools();
enable_services();
user_mod();
libvirt_hook();
}
catch (const std::runtime_error &err)
{
std::cerr << err.what() << std::endl;
return -1;
}
}

@ -0,0 +1,16 @@
#include <shell.h>
std::string shell_cmd(char const *cmd)
{
std::array<char, 128> buffer;
std::string resp;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe)
throw std::runtime_error("\n\033[1;31mThat was unexpected!\033[0m");
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
{
resp += buffer.data();
}
return resp;
}

@ -0,0 +1,41 @@
#include <sysinfo.h>
std::string get_cpu_vendor()
{
std::string cpu = "intel";
std::string res = shell_cmd("lspci | grep -i amd");
if (!res.empty())
cpu = "amd";
return cpu;
}
std::string get_gpu_vendor()
{
std::string gpu = "amd";
std::string res = shell_cmd("lspci | grep -i nvidia");
if (!res.empty())
gpu = "nvidia";
return gpu;
}
std::string get_vga_slot()
{
std::string c = "lspci | grep -i vga.*" + get_gpu_vendor();
std::string res = shell_cmd((char *)&c);
if (res.empty())
throw std::runtime_error("\n\033[1;31mCouldn't fetch VGA PCI slot!\033[0m");
return "0000:" + res.substr(0, res.find(" "));
}
std::string get_audio_slot()
{
std::string c = "lspci | grep -i audio.*" + get_gpu_vendor();
std::string res = shell_cmd((char *)&c);
if (res.empty())
throw std::runtime_error("\n\033[1;31mCouldn't fetch Audio PCI slot!\033[0m");
return "0000:" + res.substr(0, res.find(" "));
}

@ -0,0 +1,58 @@
#include <tools.h>
void install_tools()
{
struct stat buf;
if (stat("/etc/arch-release", &buf) == 0)
system("pacman -S qemu libvirt edk2-ovmf virt-manager dnsmasq ebtables");
else if (stat("/etc/gentoo-release", &buf) == 0)
system("emerge -a qemu libvirt virt-manager dnsmasq ebtables");
else if (stat("/etc/debian_version", &buf) == 0)
system("apt install qemu-kvm libvirt-clients libvirt-daemon-system ovmf dnsmasq ebtables");
else if (stat("/etc/fedora-release", &buf) == 0)
system("dnf install @virtualization");
else
throw std::runtime_error("\n\033[1;31mUnsupported system. Install required tools manually.\033[0m");
}
void enable_services()
{
std::string init_sys = get_init();
if (init_sys == "systemd")
system("systemctl enable --now libvirtd");
else // Other init systems?
std::cout << "Enable libvirtd service on your system manually..\n";
std::string res = shell_cmd("virsh net-list --all | grep -i default");
if (res.empty())
{
system("virsh net-start default");
system("virsh net-autostart default");
}
}
std::string get_init()
{
std::ifstream bin("/sbin/init", std::ios::binary);
std::string line;
while (std::getline(bin, line))
{
if (line.find("/lib/systemd") != std::string::npos)
return "systemd";
else if (line.find("sysvinit") != std::string::npos)
return "sysvinit";
else if (line.find("upstart") != std::string::npos)
return "upstart";
}
return "";
}
void user_mod()
{
std::string res = shell_cmd("usermod -aG kvm,input,libvirt $(logname)");
if (!res.empty())
{
std::string emsg = "\n\033[1;31m" + res + "\033[0m";
throw std::runtime_error(emsg);
}
}
Loading…
Cancel
Save