package profile import ( "context" "os" "path/filepath" "sort" "strings" ) // A seat is somewhere a display server could run: a graphics device with a display attached. // // **Not the same question as `graphical-session`**, and the difference is what makes it worth // having. That one asks whether a session is running *now*, which is state; this asks whether one // could ever run here, which is hardware. Deciding whether to assign a display server needs the // second — a headless server can never have one, a workstation with nothing installed yet can, // and until this existed those two looked identical. The mesh would have assigned xorg to the // server and found out at apply time. // // **`seat` rather than `display`, and the distinction matters most on a phone.** An Android // device plainly has a screen and has no seat: nothing there is going to take a DRM device and // present an X or Wayland session on it. A capability called `display` would answer *yes* and be // useless; `seat` answers *no*, which is the true and useful answer. // // The term is logind's, and it means what is wanted here: a set of hardware one person sits at. // SeatSource is where the kernel reports what is attached. A variable so a test can point it at a // directory it made, rather than at whatever this machine happens to have. var SeatSource = "/sys/class/drm" type seat struct{} func (seat) Name() string { return CapSeat } func (seat) Detect(context.Context) Verdict { const how = "/sys/class/drm/*/status — a connector the kernel reports as connected" entries, err := os.ReadDir(SeatSource) if err != nil { // No DRM subsystem at all: a container, a phone, a machine with no graphics stack. Said // as what was looked for rather than as an error, because this is the ordinary answer on // most nodes and not a fault on any of them. return Verdict{ Name: CapSeat, Present: false, Detail: "no graphics devices are present (" + SeatSource + " is not readable)", How: how, } } var connected, disconnected []string for _, e := range entries { status, err := os.ReadFile(filepath.Join(SeatSource, e.Name(), "status")) if err != nil { // Cards themselves have no status file; only connectors do. Skipping is right and // not a failure to report. continue } switch strings.TrimSpace(string(status)) { case "connected": connected = append(connected, e.Name()) default: disconnected = append(disconnected, e.Name()) } } sort.Strings(connected) if len(connected) > 0 { return Verdict{ Name: CapSeat, Present: true, Detail: strings.Join(connected, ", "), How: how, } } if len(disconnected) > 0 { // The distinction worth drawing: this machine has graphics hardware and nothing plugged // into it. A server with a GPU and no monitor, which is a different thing from a machine // with no graphics at all — and a person deciding where a desktop goes wants to know // which they are looking at. return Verdict{ Name: CapSeat, Present: false, Detail: "a graphics device with no display attached", How: how, } } return Verdict{ Name: CapSeat, Present: false, Detail: "no display connectors are present", How: how, } }