mirror of
https://github.com/luckfox-eng29/kvm.git
synced 2026-01-18 03:28:19 +01:00
Update App version to 0.0.2
This commit is contained in:
@@ -36,8 +36,9 @@ type NetworkConfig struct {
|
||||
Hostname null.String `json:"hostname,omitempty" validate_type:"hostname"`
|
||||
Domain null.String `json:"domain,omitempty" validate_type:"hostname"`
|
||||
|
||||
IPv4Mode null.String `json:"ipv4_mode,omitempty" one_of:"dhcp,static,disabled" default:"dhcp"`
|
||||
IPv4Static *IPv4StaticConfig `json:"ipv4_static,omitempty" required_if:"IPv4Mode=static"`
|
||||
IPv4Mode null.String `json:"ipv4_mode,omitempty" one_of:"dhcp,static,disabled" default:"dhcp"`
|
||||
IPv4RequestAddress null.String `json:"ipv4_request_address,omitempty"`
|
||||
IPv4Static *IPv4StaticConfig `json:"ipv4_static,omitempty" required_if:"IPv4Mode=static"`
|
||||
|
||||
IPv6Mode null.String `json:"ipv6_mode,omitempty" one_of:"slaac,dhcpv6,slaac_and_dhcpv6,static,link_local,disabled" default:"slaac"`
|
||||
IPv6Static *IPv6StaticConfig `json:"ipv6_static,omitempty" required_if:"IPv6Mode=static"`
|
||||
|
||||
@@ -95,6 +95,7 @@ func NewNetworkInterfaceState(opts *NetworkInterfaceOptions) (*NetworkInterfaceS
|
||||
|
||||
opts.OnDhcpLeaseChange(lease)
|
||||
},
|
||||
RequestAddress: s.config.IPv4RequestAddress.String,
|
||||
})
|
||||
|
||||
s.dhcpClient = dhcpClient
|
||||
|
||||
@@ -3,10 +3,13 @@ package udhcpc
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
@@ -21,20 +24,22 @@ const (
|
||||
)
|
||||
|
||||
type DHCPClient struct {
|
||||
InterfaceName string
|
||||
leaseFile string
|
||||
pidFile string
|
||||
lease *Lease
|
||||
logger *zerolog.Logger
|
||||
process *os.Process
|
||||
onLeaseChange func(lease *Lease)
|
||||
InterfaceName string
|
||||
leaseFile string
|
||||
pidFile string
|
||||
requestAddress string
|
||||
lease *Lease
|
||||
logger *zerolog.Logger
|
||||
process *os.Process
|
||||
onLeaseChange func(lease *Lease)
|
||||
}
|
||||
|
||||
type DHCPClientOptions struct {
|
||||
InterfaceName string
|
||||
PidFile string
|
||||
Logger *zerolog.Logger
|
||||
OnLeaseChange func(lease *Lease)
|
||||
InterfaceName string
|
||||
PidFile string
|
||||
Logger *zerolog.Logger
|
||||
OnLeaseChange func(lease *Lease)
|
||||
RequestAddress string
|
||||
}
|
||||
|
||||
var defaultLogger = zerolog.New(os.Stdout).Level(zerolog.InfoLevel)
|
||||
@@ -46,11 +51,12 @@ func NewDHCPClient(options *DHCPClientOptions) *DHCPClient {
|
||||
|
||||
l := options.Logger.With().Str("interface", options.InterfaceName).Logger()
|
||||
return &DHCPClient{
|
||||
InterfaceName: options.InterfaceName,
|
||||
logger: &l,
|
||||
leaseFile: fmt.Sprintf(DHCPLeaseFile, options.InterfaceName),
|
||||
pidFile: options.PidFile,
|
||||
onLeaseChange: options.OnLeaseChange,
|
||||
InterfaceName: options.InterfaceName,
|
||||
logger: &l,
|
||||
leaseFile: fmt.Sprintf(DHCPLeaseFile, options.InterfaceName),
|
||||
pidFile: options.PidFile,
|
||||
onLeaseChange: options.OnLeaseChange,
|
||||
requestAddress: options.RequestAddress,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +86,8 @@ func (c *DHCPClient) watchLink() {
|
||||
|
||||
for update := range ch {
|
||||
if update.Link.Attrs().Name == c.InterfaceName {
|
||||
if update.IfInfomsg.Flags&unix.IFF_RUNNING != 0 {
|
||||
fmt.Printf("[watchLink]link is up, starting udhcpc")
|
||||
if update.Flags&unix.IFF_RUNNING != 0 {
|
||||
c.logger.Info().Msg("link is up, starting udhcpc")
|
||||
go c.runUDHCPC()
|
||||
} else {
|
||||
c.logger.Info().Msg("link is down")
|
||||
@@ -90,10 +96,45 @@ func (c *DHCPClient) watchLink() {
|
||||
}
|
||||
}
|
||||
|
||||
type udhcpcOutput struct {
|
||||
mu *sync.Mutex
|
||||
logger *zerolog.Event
|
||||
}
|
||||
|
||||
func (w *udhcpcOutput) Write(p []byte) (n int, err error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
w.logger.Msg(string(p))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (c *DHCPClient) runUDHCPC() {
|
||||
cmd := exec.Command("udhcpc", "-i", c.InterfaceName, "-t", "1")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if c.requestAddress != "" {
|
||||
ip := net.ParseIP(c.requestAddress)
|
||||
if ip != nil && ip.To4() != nil {
|
||||
cmd.Args = append(cmd.Args, "-r", c.requestAddress)
|
||||
}
|
||||
}
|
||||
|
||||
udhcpcOutputLock := sync.Mutex{}
|
||||
udhcpcStdout := &udhcpcOutput{
|
||||
mu: &udhcpcOutputLock,
|
||||
logger: c.logger.Debug().Str("pipe", "stdout"),
|
||||
}
|
||||
udhcpcStderr := &udhcpcOutput{
|
||||
mu: &udhcpcOutputLock,
|
||||
logger: c.logger.Debug().Str("pipe", "stderr"),
|
||||
}
|
||||
|
||||
cmd.Stdout = udhcpcStdout
|
||||
cmd.Stderr = udhcpcStderr
|
||||
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
Setpgid: true,
|
||||
Pdeathsig: syscall.SIGKILL,
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
c.logger.Error().Err(err).Msg("failed to run udhcpc")
|
||||
}
|
||||
@@ -113,6 +154,7 @@ func (c *DHCPClient) Run() error {
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
go c.runUDHCPC()
|
||||
go c.watchLink()
|
||||
|
||||
go func() {
|
||||
|
||||
@@ -34,6 +34,7 @@ const (
|
||||
FileStateFileWrite // update file content without checking
|
||||
FileStateMounted
|
||||
FileStateMountedConfigFS
|
||||
FileStateMountedFunctionFS
|
||||
FileStateSymlink
|
||||
FileStateSymlinkInOrderConfigFS // configfs is a shithole, so we need to check if the symlinks are created in the correct order
|
||||
FileStateSymlinkNotInOrderConfigFS
|
||||
@@ -52,6 +53,7 @@ var FileStateString = map[FileState]string{
|
||||
FileStateSymlink: "SYMLINK",
|
||||
FileStateSymlinkInOrderConfigFS: "SYMLINK_IN_ORDER_CONFIGFS",
|
||||
FileStateTouch: "TOUCH",
|
||||
FileStateMountedFunctionFS: "FUNCTIONFS_MOUNTED",
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -78,6 +80,7 @@ const (
|
||||
FileChangeResolvedActionRemoveDirectory
|
||||
FileChangeResolvedActionTouch
|
||||
FileChangeResolvedActionMountConfigFS
|
||||
FileChangeResolvedActionMountFunctionFS
|
||||
)
|
||||
|
||||
var FileChangeResolvedActionString = map[FileChangeResolvedAction]string{
|
||||
@@ -96,6 +99,7 @@ var FileChangeResolvedActionString = map[FileChangeResolvedAction]string{
|
||||
FileChangeResolvedActionRemoveDirectory: "DIR_REMOVE",
|
||||
FileChangeResolvedActionTouch: "TOUCH",
|
||||
FileChangeResolvedActionMountConfigFS: "CONFIGFS_MOUNT",
|
||||
FileChangeResolvedActionMountFunctionFS: "FUNCTIONFS_MOUNT",
|
||||
}
|
||||
|
||||
type ChangeSet struct {
|
||||
@@ -147,6 +151,8 @@ func (f *RequestedFileChange) String() string {
|
||||
s = fmt.Sprintf("write: %s with content [%s]", f.Path, f.ExpectedContent)
|
||||
case FileStateMountedConfigFS:
|
||||
s = fmt.Sprintf("configfs: %s", f.Path)
|
||||
case FileStateMountedFunctionFS:
|
||||
s = fmt.Sprintf("functionfs: %s", f.Path)
|
||||
case FileStateTouch:
|
||||
s = fmt.Sprintf("touch: %s", f.Path)
|
||||
case FileStateUnknown:
|
||||
@@ -298,6 +304,8 @@ func (fc *FileChange) getFileChangeResolvedAction() FileChangeResolvedAction {
|
||||
return FileChangeResolvedActionWriteFile
|
||||
case FileStateTouch:
|
||||
return FileChangeResolvedActionTouch
|
||||
case FileStateMountedFunctionFS:
|
||||
return FileChangeResolvedActionMountFunctionFS
|
||||
}
|
||||
|
||||
// get the actual state of the file
|
||||
@@ -424,6 +432,8 @@ func (c *ChangeSet) applyChange(change *FileChange) error {
|
||||
return os.Chtimes(change.Path, time.Now(), time.Now())
|
||||
case FileChangeResolvedActionMountConfigFS:
|
||||
return mountConfigFS(change.Path)
|
||||
case FileChangeResolvedActionMountFunctionFS:
|
||||
return mountFunctionFS(change.Path)
|
||||
case FileChangeResolvedActionDoNothing:
|
||||
return nil
|
||||
default:
|
||||
|
||||
@@ -2,6 +2,7 @@ package usbgadget
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/sourcegraph/tf-dag/dag"
|
||||
@@ -127,6 +128,11 @@ func (c *ChangeSetResolver) applyChanges() error {
|
||||
l.Str("action", actionStr).Str("change", change.String()).Msg("applying change")
|
||||
|
||||
err := c.changeset.applyChange(change)
|
||||
if err != nil {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
err = c.changeset.applyChange(change)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if change.IgnoreErrors {
|
||||
c.l.Warn().Str("change", change.String()).Err(err).Msg("ignoring error")
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package usbgadget
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type gadgetConfigItem struct {
|
||||
@@ -51,6 +54,8 @@ var defaultGadgetConfig = map[string]gadgetConfigItem{
|
||||
"configuration": "Config 1: HID",
|
||||
},
|
||||
},
|
||||
// mtp
|
||||
"mtp": mtpConfig,
|
||||
// keyboard HID
|
||||
"keyboard": keyboardConfig,
|
||||
// mouse HID
|
||||
@@ -91,6 +96,8 @@ func (u *UsbGadget) isGadgetConfigItemEnabled(itemKey string) bool {
|
||||
return u.enabledDevices.MassStorage
|
||||
case "mass_storage_lun0":
|
||||
return u.enabledDevices.MassStorage
|
||||
case "mtp":
|
||||
return u.enabledDevices.Mtp
|
||||
case "audio":
|
||||
return u.enabledDevices.Audio
|
||||
default:
|
||||
@@ -184,6 +191,45 @@ func mountConfigFS(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func mountFunctionFS(path string) error {
|
||||
err := os.MkdirAll("/dev/ffs-mtp", 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create mtp dev dir: %w", err)
|
||||
}
|
||||
mounted := false
|
||||
if f, err := os.Open("/proc/mounts"); err == nil {
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
if strings.Contains(scanner.Text(), functionFSPath) {
|
||||
mounted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
if !mounted {
|
||||
err := exec.Command("mount", "-t", "functionfs", "mtp", path).Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mount functionfs: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
umtprdRunning := false
|
||||
if out, err := exec.Command("pgrep", "-x", "umtprd").Output(); err == nil && len(out) > 0 {
|
||||
umtprdRunning = true
|
||||
}
|
||||
|
||||
if !umtprdRunning {
|
||||
cmd := exec.Command("umtprd")
|
||||
if err := cmd.Start(); err != nil {
|
||||
return fmt.Errorf("failed to exec binary: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *UsbGadget) Init() error {
|
||||
u.configLock.Lock()
|
||||
defer u.configLock.Unlock()
|
||||
|
||||
@@ -131,6 +131,16 @@ func (tx *UsbGadgetTransaction) MountConfigFS() {
|
||||
})
|
||||
}
|
||||
|
||||
func (tx *UsbGadgetTransaction) MountFunctionFS() {
|
||||
tx.addFileChange("mtp", RequestedFileChange{
|
||||
Path: functionFSPath,
|
||||
Key: "mtp",
|
||||
ExpectedState: FileStateMountedFunctionFS,
|
||||
Description: "mount functionfs",
|
||||
DependsOn: []string{"reorder-symlinks"},
|
||||
})
|
||||
}
|
||||
|
||||
func (tx *UsbGadgetTransaction) CreateConfigPath() {
|
||||
tx.mkdirAll(
|
||||
"gadget",
|
||||
@@ -164,7 +174,12 @@ func (tx *UsbGadgetTransaction) WriteGadgetConfig() {
|
||||
deps = tx.writeGadgetItemConfig(item, deps)
|
||||
}
|
||||
|
||||
tx.WriteUDC()
|
||||
if tx.isGadgetConfigItemEnabled("mtp") {
|
||||
tx.MountFunctionFS()
|
||||
tx.WriteUDC(true)
|
||||
} else {
|
||||
tx.WriteUDC(false)
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *UsbGadgetTransaction) getDisableKeys() []string {
|
||||
@@ -315,17 +330,28 @@ func (tx *UsbGadgetTransaction) addReorderSymlinkChange(path string, target stri
|
||||
})
|
||||
}
|
||||
|
||||
func (tx *UsbGadgetTransaction) WriteUDC() {
|
||||
func (tx *UsbGadgetTransaction) WriteUDC(mtpServer bool) {
|
||||
// bound the gadget to a UDC (USB Device Controller)
|
||||
path := path.Join(tx.kvmGadgetPath, "UDC")
|
||||
tx.addFileChange("udc", RequestedFileChange{
|
||||
Key: "udc",
|
||||
Path: path,
|
||||
ExpectedState: FileStateFileContentMatch,
|
||||
ExpectedContent: []byte(tx.udc),
|
||||
DependsOn: []string{"reorder-symlinks"},
|
||||
Description: "write UDC",
|
||||
})
|
||||
if mtpServer {
|
||||
tx.addFileChange("udc", RequestedFileChange{
|
||||
Key: "udc",
|
||||
Path: path,
|
||||
ExpectedState: FileStateFileContentMatch,
|
||||
ExpectedContent: []byte(tx.udc),
|
||||
DependsOn: []string{"mtp"},
|
||||
Description: "write UDC",
|
||||
})
|
||||
} else {
|
||||
tx.addFileChange("udc", RequestedFileChange{
|
||||
Key: "udc",
|
||||
Path: path,
|
||||
ExpectedState: FileStateFileContentMatch,
|
||||
ExpectedContent: []byte(tx.udc),
|
||||
DependsOn: []string{"reorder-symlinks"},
|
||||
Description: "write UDC",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *UsbGadgetTransaction) RebindUsb(ignoreUnbindError bool) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
package usbgadget
|
||||
|
||||
const dwc3Path = "/sys/bus/platform/drivers/dwc3"
|
||||
const udcPath = "/sys/kernel/config/usb_gadget/kvm/UDC"
|
||||
|
||||
@@ -23,3 +23,10 @@ var massStorageLun0Config = gadgetConfigItem{
|
||||
"inquiry_string": "KVM Virtual Media",
|
||||
},
|
||||
}
|
||||
|
||||
var mtpConfig = gadgetConfigItem{
|
||||
order: 3003,
|
||||
device: "ffs.mtp",
|
||||
path: []string{"functions", "ffs.mtp"},
|
||||
configPath: []string{"ffs.mtp"},
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func (u *UsbGadget) IsUDCBound() (bool, error) {
|
||||
|
||||
// BindUDC binds the gadget to the UDC.
|
||||
func (u *UsbGadget) BindUDC() error {
|
||||
err := os.WriteFile(path.Join(dwc3Path, "bind"), []byte(u.udc), 0644)
|
||||
err := os.WriteFile(path.Join(udcPath, "bind"), []byte(u.udc), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error binding UDC: %w", err)
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (u *UsbGadget) BindUDC() error {
|
||||
|
||||
// UnbindUDC unbinds the gadget from the UDC.
|
||||
func (u *UsbGadget) UnbindUDC() error {
|
||||
err := os.WriteFile(path.Join(dwc3Path, "unbind"), []byte(u.udc), 0644)
|
||||
err := os.WriteFile(path.Join(udcPath, " "), []byte(u.udc), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unbinding UDC: %w", err)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ type Devices struct {
|
||||
RelativeMouse bool `json:"relative_mouse"`
|
||||
Keyboard bool `json:"keyboard"`
|
||||
MassStorage bool `json:"mass_storage"`
|
||||
Mtp bool `json:"mtp"`
|
||||
Audio bool `json:"audio"`
|
||||
}
|
||||
|
||||
@@ -88,6 +89,9 @@ type UsbGadget struct {
|
||||
const configFSPath = "/sys/kernel/config"
|
||||
const gadgetPath = "/sys/kernel/config/usb_gadget"
|
||||
|
||||
const functionFSPath = "/dev/ffs-mtp"
|
||||
const umtprdPath = "/usr/sbin/umtprd"
|
||||
|
||||
var defaultLogger = logging.GetSubsystemLogger("usbgadget")
|
||||
|
||||
// NewUsbGadget creates a new UsbGadget.
|
||||
|
||||
Reference in New Issue
Block a user