@@ -9,6 +9,10 @@ import (
99 "context"
1010 "fmt"
1111 "strconv"
12+ "strings"
13+
14+ "github.com/siderolabs/go-pointer"
15+ "github.com/siderolabs/go-procfs/procfs"
1216
1317 "github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
1418 "github.com/siderolabs/talos/internal/app/machined/pkg/system/events"
@@ -25,18 +29,57 @@ import (
2529// the required methods.
2630type Dashboard struct {}
2731
32+ // getCustomConsole returns the custom console parameter value if specified, empty string otherwise.
33+ func (d * Dashboard ) getCustomConsole () string {
34+ consoleParam := procfs .ProcCmdline ().Get (constants .KernelParamDashboardConsole ).First ()
35+
36+ return pointer .SafeDeref (consoleParam )
37+ }
38+
39+ // hasCustomConsole checks if a custom console is specified via kernel parameter.
40+ func (d * Dashboard ) hasCustomConsole () bool {
41+ return d .getCustomConsole () != ""
42+ }
43+
44+ // getConsoleDevice returns the console device path to use for the dashboard.
45+ func (d * Dashboard ) getConsoleDevice () (string , error ) {
46+ consoleName := d .getCustomConsole ()
47+
48+ if consoleName != "" {
49+ // Validate that the console name starts with "tty"
50+ if ! strings .HasPrefix (consoleName , "tty" ) || strings .Contains (consoleName , "/" ) {
51+ return "" , fmt .Errorf ("invalid console name %q: must start with 'tty'" , consoleName )
52+ }
53+
54+ return fmt .Sprintf ("/dev/%s" , consoleName ), nil
55+ }
56+
57+ // Default to the standard dashboard TTY
58+ return fmt .Sprintf ("/dev/tty%d" , constants .DashboardTTY ), nil
59+ }
60+
2861// ID implements the Service interface.
2962func (d * Dashboard ) ID (_ runtime.Runtime ) string {
3063 return "dashboard"
3164}
3265
3366// PreFunc implements the Service interface.
3467func (d * Dashboard ) PreFunc (_ context.Context , _ runtime.Runtime ) error {
68+ // Skip TTY switching if a custom console is specified
69+ if d .hasCustomConsole () {
70+ return nil
71+ }
72+
3573 return console .Switch (constants .DashboardTTY )
3674}
3775
3876// PostFunc implements the Service interface.
3977func (d * Dashboard ) PostFunc (_ runtime.Runtime , _ events.ServiceState ) error {
78+ // Skip TTY switching if a custom console is specified
79+ if d .hasCustomConsole () {
80+ return nil
81+ }
82+
4083 return console .Switch (constants .KernelLogsTTY )
4184}
4285
@@ -57,7 +100,10 @@ func (d *Dashboard) Volumes(runtime.Runtime) []string {
57100
58101// Runner implements the Service interface.
59102func (d * Dashboard ) Runner (r runtime.Runtime ) (runner.Runner , error ) {
60- tty := fmt .Sprintf ("/dev/tty%d" , constants .DashboardTTY )
103+ tty , err := d .getConsoleDevice ()
104+ if err != nil {
105+ return nil , fmt .Errorf ("failed to determine console device: %w" , err )
106+ }
61107
62108 return restart .New (process .NewRunner (false , & runner.Args {
63109 ID : d .ID (r ),
0 commit comments