rs2322tcp/internal/client/virtual_port_validation_linux.go

106 lines
2.7 KiB
Go

//go:build linux
/*
* ============================================================================
* Projekt.....: rs2322tcp
* Datei.......: internal/client/virtual_port_validation_linux.go
* Copyright (C) 2026 Dieter Lang
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Beschreibung:
* Linux-spezifische Ermittlung der lokal vorhandenen virtuellen
* rs2322tcp-Schnittstellen.
*
* Die öffentliche /dev/ttyUSBxxx-Schnittstelle wird ausschließlich gelesen.
* Der Client verändert diese Schnittstellen hier nicht.
* ============================================================================
*/
package client
import (
"fmt"
"os"
"path/filepath"
"git.lang-dieter.de/rs2322tcp/internal/config"
)
///////////////////////////////////////////////////////////////////////////////
// Existing virtual ports
///////////////////////////////////////////////////////////////////////////////
// existingVirtualPortLinks returns all public virtual-port paths that
// currently exist as symbolic links.
//
// Only ports inside the configured virtual-port range are considered.
// The public /dev/ttyUSBxxx links are only inspected; they are never
// created, changed, or removed by this function.
//
// This check only requires read access and therefore does not require
// root privileges.
func existingVirtualPortLinks(
cfg config.VirtualPortRangeConfig,
) ([]string, error) {
return existingVirtualPortLinksInDirectory(
cfg,
"/dev",
)
}
///////////////////////////////////////////////////////////////////////////////
// Existing virtual ports in directory
///////////////////////////////////////////////////////////////////////////////
// existingVirtualPortLinksInDirectory returns all virtual-port paths in
// directory that currently exist as symbolic links.
//
// This helper is deliberately separated from existingVirtualPortLinks so
// the filesystem inspection can be tested without modifying /dev.
func existingVirtualPortLinksInDirectory(
cfg config.VirtualPortRangeConfig,
directory string,
) ([]string, error) {
if directory == "" {
return nil, fmt.Errorf("virtual port directory is empty")
}
manager := NewVirtualPortManager(cfg)
if manager == nil {
return nil, fmt.Errorf("virtual port manager is nil")
}
links := make([]string, 0)
for number := cfg.First; number <= cfg.Last; number++ {
portName := filepath.Base(
manager.PortPath(number),
)
portPath := filepath.Join(directory, portName)
info, err := os.Lstat(portPath)
if err != nil {
if os.IsNotExist(err) {
continue
}
return nil, fmt.Errorf(
"inspect virtual port %q: %w",
portPath,
err,
)
}
if info.Mode()&os.ModeSymlink == 0 {
continue
}
links = append(
links,
filepath.Join(directory, portName),
)
}
return links, nil
}