This commit is contained in:
bluepython508 committed 2026-10-22 12:27:19 +01:00
1 parent 3530afb854
commit 6903fcff27
2146 files changed
+112256 -190703

No files matched your search

+103 -8
View File
@@ -1,4 +1,4 @@
// Copyright (c) Tailscale Inc & AUTHORS
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
//go:build linux && !android
@@ -7,11 +7,14 @@ package hostinfo
import (
"bytes"
"context"
"encoding/json"
"os"
"os/exec"
"strings"
"time"
"golang.org/x/sys/unix"
"tailscale.com/types/ptr"
"tailscale.com/util/lineiter"
"tailscale.com/version/distro"
)
@@ -23,11 +26,12 @@ func init() {
distroVersion = distroVersionLinux
distroCodeName = distroCodeNameLinux
deviceModel = deviceModelLinux
systemdLogindDesktop = hasLogindDesktop
}
var (
lazyVersionMeta = &lazyAtomicValue[versionMeta]{f: ptr.To(linuxVersionMeta)}
lazyOSVersion = &lazyAtomicValue[string]{f: ptr.To(osVersionLinux)}
lazyVersionMeta = &lazyAtomicValue[versionMeta]{f: new(linuxVersionMeta)}
lazyOSVersion = &lazyAtomicValue[string]{f: new(osVersionLinux)}
)
type versionMeta struct {
@@ -69,7 +73,7 @@ func deviceModelLinux() string {
}
func getQnapQtsVersion(versionInfo string) string {
for _, field := range strings.Fields(versionInfo) {
for field := range strings.FieldsSeq(versionInfo) {
if suffix, ok := strings.CutPrefix(field, "QTSFW_"); ok {
return suffix
}
@@ -111,11 +115,11 @@ func linuxVersionMeta() (meta versionMeta) {
if err != nil {
break
}
eq := bytes.IndexByte(line, '=')
if eq == -1 {
before, after, ok := bytes.Cut(line, []byte{'='})
if !ok {
continue
}
k, v := string(line[:eq]), strings.Trim(string(line[eq+1:]), `"'`)
k, v := string(before), strings.Trim(string(after), `"'`)
m[k] = v
}
@@ -178,3 +182,94 @@ func packageTypeLinux() string {
}
return ""
}
// hasLogindDesktop calls [systemdLogindFindDesktop] with a 100 millisecond
// timeout.
func hasLogindDesktop() bool {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
runner := &osLogindRunner{ctx: ctx}
return systemdLogindFindDesktop(runner)
}
// logindConn is the interface for querying systemd-logind session information.
// It exists to be able to swap the backend for testing.
type logindRunner interface {
// listSessions returns the raw JSON output of
// "loginctl list-sessions --json=short", which is a json blob containing
// output like: '[{"session":"8"},{"session":"9"}]'.
listSessions() ([]byte, error)
// getSessionType returns the raw output of
// "loginctl show-session <id> --property=Type", which is a single line of
// the form "Type=<value>".
getSessionType(string) (string, error)
}
// osLogindRunner implements [logindRunner] by shelling out to the system logind.
type osLogindRunner struct{ ctx context.Context }
// listSessions implements [logindRunner] using os calls.
func (r *osLogindRunner) listSessions() ([]byte, error) {
path, err := exec.LookPath("loginctl")
if err != nil {
return nil, err
}
cmd := exec.CommandContext(r.ctx, path, "list-sessions", "--json=short")
output, err := cmd.Output()
if err != nil {
return nil, err
}
return output, nil
}
// getSessionType implements [logindRunner] using os calls.
func (r *osLogindRunner) getSessionType(session string) (string, error) {
path, err := exec.LookPath("loginctl")
if err != nil {
return "", err
}
cmd := exec.CommandContext(r.ctx,
path, "show-session", session, "--property=Type", "--value")
output, err := cmd.Output()
if err != nil {
return "", err
}
return string(output), nil
}
// systemdLogindFindDesktop reports whether any active logind session has a
// graphical desktop type (x11, wayland, or mir). On an error or with no types
// matching the list above, it returns false.
func systemdLogindFindDesktop(logind logindRunner) bool {
sessionJSON, err := logind.listSessions()
if err != nil {
return false
}
type session struct {
Session string `json:"session"`
}
var sessions []session
err = json.Unmarshal(sessionJSON, &sessions)
if err != nil {
return false
}
for _, sess := range sessions {
typeString, err := logind.getSessionType(sess.Session)
if err != nil {
continue
}
switch strings.ToLower(strings.TrimSpace(typeString)) {
case "wayland", "x11", "mir":
return true
}
}
return false
}