140 lines
3.3 KiB
Go
140 lines
3.3 KiB
Go
//go:build linux
|
|
|
|
/*
|
|
* ============================================================================
|
|
* Projekt.....: rs2322tcp
|
|
* Datei.......: internal/client/virtual_port_linux.go
|
|
* Copyright (C) 2026 Dieter Lang
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* Beschreibung:
|
|
* Linux-spezifische Verwaltung der internen Symlinks für virtuelle
|
|
* rs2322tcp-Seriellschnittstellen.
|
|
*
|
|
* Der öffentliche Gerätename /dev/ttyUSBxxx wird bei der Installation
|
|
* vorbereitet. Der Client verwaltet ausschließlich den benutzerbezogenen
|
|
* Link unter ~/.rs2322tcp/virtual/.
|
|
* ============================================================================
|
|
*/
|
|
package client
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
const (
|
|
virtualDirectoryName = ".rs2322tcp/virtual"
|
|
)
|
|
|
|
// virtualPortDirectory returns the directory in the current user's home
|
|
// directory used for the internal virtual-port links.
|
|
func virtualPortDirectory() (string, error) {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return "", fmt.Errorf("get user home directory: %w", err)
|
|
}
|
|
|
|
return filepath.Join(home, virtualDirectoryName), nil
|
|
}
|
|
|
|
// virtualPortLinkPath returns the path of the internal link for a virtual
|
|
// serial port.
|
|
func virtualPortLinkPath(portPath string) (string, error) {
|
|
directory, err := virtualPortDirectory()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return filepath.Join(directory, filepath.Base(portPath)), nil
|
|
}
|
|
|
|
// ensureVirtualPortDirectory creates the internal virtual-port directory
|
|
// if it does not already exist.
|
|
func ensureVirtualPortDirectory() error {
|
|
directory, err := virtualPortDirectory()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := os.MkdirAll(directory, 0755); err != nil {
|
|
return fmt.Errorf(
|
|
"create virtual port directory %q: %w",
|
|
directory,
|
|
err,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// setVirtualPortLink creates or replaces the internal link for a virtual
|
|
// port.
|
|
//
|
|
// The link itself is located below ~/.rs2322tcp/virtual/ and points to the
|
|
// current PTY, for example /dev/pts/2.
|
|
func setVirtualPortLink(portPath string, target string) error {
|
|
if portPath == "" {
|
|
return fmt.Errorf("virtual port path is empty")
|
|
}
|
|
|
|
if target == "" {
|
|
return fmt.Errorf("virtual port target is empty")
|
|
}
|
|
|
|
if err := ensureVirtualPortDirectory(); err != nil {
|
|
return err
|
|
}
|
|
|
|
linkPath, err := virtualPortLinkPath(portPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Remove an existing link. The installation-owned outer /dev/ttyUSBxxx
|
|
// link is deliberately never touched here.
|
|
if err := os.Remove(linkPath); err != nil && !os.IsNotExist(err) {
|
|
return fmt.Errorf(
|
|
"remove existing virtual port link %q: %w",
|
|
linkPath,
|
|
err,
|
|
)
|
|
}
|
|
|
|
if err := os.Symlink(target, linkPath); err != nil {
|
|
return fmt.Errorf(
|
|
"create virtual port link %q -> %q: %w",
|
|
linkPath,
|
|
target,
|
|
err,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// removeVirtualPortLink removes the internal link for a virtual port.
|
|
//
|
|
// The public /dev/ttyUSBxxx link is never modified.
|
|
func removeVirtualPortLink(portPath string) error {
|
|
if portPath == "" {
|
|
return fmt.Errorf("virtual port path is empty")
|
|
}
|
|
|
|
linkPath, err := virtualPortLinkPath(portPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := os.Remove(linkPath); err != nil && !os.IsNotExist(err) {
|
|
return fmt.Errorf(
|
|
"remove virtual port link %q: %w",
|
|
linkPath,
|
|
err,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|