192 lines
3.8 KiB
Go
192 lines
3.8 KiB
Go
package hid
|
|
|
|
import (
|
|
"NanoKVM-Server/proto"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
ModeNormal = "normal"
|
|
ModeHidOnly = "hid-only"
|
|
ModeFlag = "/sys/kernel/config/usb_gadget/g0/bcdDevice"
|
|
|
|
ModeNormalScript = "/kvmapp/system/init.d/S03usbdev"
|
|
ModeHidOnlyScript = "/kvmapp/system/init.d/S03usbhid"
|
|
|
|
USBDevScript = "/etc/init.d/S03usbdev"
|
|
)
|
|
|
|
var modeMap = map[string]string{
|
|
"0x0510": ModeNormal,
|
|
"0x0623": ModeHidOnly,
|
|
}
|
|
|
|
func (s *Service) GetHidMode(c *gin.Context) {
|
|
var rsp proto.Response
|
|
|
|
mode, err := getHidMode()
|
|
if err != nil {
|
|
rsp.ErrRsp(c, -1, "get HID mode failed")
|
|
return
|
|
}
|
|
|
|
rsp.OkRspWithData(c, &proto.GetHidModeRsp{
|
|
Mode: mode,
|
|
})
|
|
log.Debugf("get hid mode: %s", mode)
|
|
}
|
|
|
|
func (s *Service) SetHidMode(c *gin.Context) {
|
|
var req proto.SetHidModeReq
|
|
var rsp proto.Response
|
|
|
|
if err := proto.ParseFormRequest(c, &req); err != nil {
|
|
rsp.ErrRsp(c, -1, "invalid arguments")
|
|
return
|
|
}
|
|
if req.Mode != ModeNormal && req.Mode != ModeHidOnly {
|
|
rsp.ErrRsp(c, -2, "invalid arguments")
|
|
return
|
|
}
|
|
|
|
if mode, _ := getHidMode(); req.Mode == mode {
|
|
rsp.OkRsp(c)
|
|
return
|
|
}
|
|
|
|
h := GetHid()
|
|
h.Lock()
|
|
h.CloseNoLock()
|
|
defer func() {
|
|
h.OpenNoLock()
|
|
h.Unlock()
|
|
}()
|
|
|
|
srcScript := ModeNormalScript
|
|
if req.Mode == ModeHidOnly {
|
|
srcScript = ModeHidOnlyScript
|
|
}
|
|
|
|
if err := copyModeFile(srcScript); err != nil {
|
|
rsp.ErrRsp(c, -3, "operation failed")
|
|
return
|
|
}
|
|
|
|
rsp.OkRsp(c)
|
|
|
|
log.Println("reboot system...")
|
|
time.Sleep(500 * time.Millisecond)
|
|
_ = exec.Command("reboot").Run()
|
|
}
|
|
|
|
func (s *Service) ResetHid(c *gin.Context) {
|
|
var rsp proto.Response
|
|
|
|
h := GetHid()
|
|
h.Lock()
|
|
h.CloseNoLock()
|
|
defer func() {
|
|
h.OpenNoLock()
|
|
h.Unlock()
|
|
}()
|
|
|
|
command := fmt.Sprintf("%s restart_phy", USBDevScript)
|
|
err := exec.Command("sh", "-c", command).Run()
|
|
if err != nil {
|
|
log.Errorf("failed to reset hid: %v", err)
|
|
rsp.ErrRsp(c, -1, "failed to reset hid")
|
|
return
|
|
}
|
|
|
|
rsp.OkRsp(c)
|
|
log.Debugf("reset hid success")
|
|
}
|
|
|
|
func copyModeFile(srcScript string) error {
|
|
// open the source file
|
|
srcFile, err := os.Open(srcScript)
|
|
if err != nil {
|
|
log.Errorf("failed to open %s: %s", srcScript, err)
|
|
return err
|
|
}
|
|
defer func() {
|
|
_ = srcFile.Close()
|
|
}()
|
|
|
|
srcInfo, err := srcFile.Stat()
|
|
if err != nil {
|
|
log.Errorf("failed to get %s info: %s", srcScript, err)
|
|
return err
|
|
}
|
|
|
|
// create and copy to temporary file
|
|
tmpFile, err := os.CreateTemp("/etc/init.d/", ".S03usbdev-")
|
|
if err != nil {
|
|
log.Errorf("failed to create temp %s: %s", USBDevScript, err)
|
|
return err
|
|
}
|
|
tmpPath := tmpFile.Name()
|
|
defer func() {
|
|
_ = os.Remove(tmpPath)
|
|
}()
|
|
log.Debugf("create temporary file: %s", tmpPath)
|
|
|
|
if err := tmpFile.Chmod(srcInfo.Mode()); err != nil {
|
|
_ = tmpFile.Close()
|
|
log.Errorf("failed to set %s mode: %s", tmpPath, err)
|
|
return err
|
|
}
|
|
|
|
if _, err := io.Copy(tmpFile, srcFile); err != nil {
|
|
_ = tmpFile.Close()
|
|
log.Errorf("failed to copy %s: %s", srcScript, err)
|
|
return err
|
|
}
|
|
|
|
if err := tmpFile.Sync(); err != nil {
|
|
_ = tmpFile.Close()
|
|
log.Errorf("failed to sync %s: %s", tmpPath, err)
|
|
return err
|
|
}
|
|
|
|
if err := tmpFile.Close(); err != nil {
|
|
log.Errorf("failed to close %s: %s", tmpPath, err)
|
|
return err
|
|
}
|
|
|
|
// replace the target file with the temporary file
|
|
if err := os.Rename(tmpPath, USBDevScript); err != nil {
|
|
log.Errorf("failed to rename %s: %s", tmpPath, err)
|
|
return err
|
|
}
|
|
|
|
log.Debugf("copy %s to %s successful", srcScript, USBDevScript)
|
|
return nil
|
|
}
|
|
|
|
func getHidMode() (string, error) {
|
|
data, err := os.ReadFile(ModeFlag)
|
|
if err != nil {
|
|
log.Errorf("failed to read %s: %s", ModeFlag, err)
|
|
return "", err
|
|
}
|
|
|
|
key := strings.TrimSpace(string(data))
|
|
mode, ok := modeMap[key]
|
|
if !ok {
|
|
log.Errorf("invalid mode flag: %s", key)
|
|
return "", errors.New("invalid mode flag")
|
|
}
|
|
|
|
return mode, nil
|
|
}
|