1package harness
2
3import (
4 "context"
5 "fmt"
6 "net"
7 "os"
8 "path/filepath"
9 "regexp"
10 "strings"
11)
12
13var sizePattern = regexp.MustCompile(`^[1-9][0-9]*x[1-9][0-9]*$`)
14var layoutPattern = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
15var socketPattern = regexp.MustCompile(`^wayland-[0-9]+$`)
16
17func Config(size, scale, layout, background string) (string, error) {
18 if !sizePattern.MatchString(size) || !layoutPattern.MatchString(layout) {
19 return "", fmt.Errorf("invalid size or layout")
20 }
21 if scale != "1" && scale != "1.25" && scale != "1.5" && scale != "2" {
22 return "", fmt.Errorf("unsupported scale %q", scale)
23 }
24 if _, err := ParseColor(background); err != nil {
25 return "", err
26 }
27 // Wayland debug logs record each client cursor shape change, which
28 // systemtests read from the compositor run log.
29 return fmt.Sprintf("output.HEADLESS-1 = %s\noutput.HEADLESS-1.scale = %s\nkeyboard.layout = %s\nbackground = %s\nlog.debug = wayland\n", size, scale, layout, background), nil
30}
31
32// DiscoverSocket only accepts a real Unix socket paired with NeferWL's state file.
33// A fresh private runtime directory prevents picking up a foreign session.
34func DiscoverSocket(ctx context.Context, runtime string) (string, error) {
35 entries, err := os.ReadDir(filepath.Join(runtime, "neferwl"))
36 if os.IsNotExist(err) {
37 return "", nil
38 }
39 if err != nil {
40 return "", err
41 }
42 var names []string
43 for _, e := range entries {
44 if err := ctx.Err(); err != nil {
45 return "", err
46 }
47 name, ok := strings.CutSuffix(e.Name(), ".json")
48 if !ok || !socketPattern.MatchString(name) {
49 continue
50 }
51 fi, err := os.Lstat(filepath.Join(runtime, name))
52 if err == nil && fi.Mode()&os.ModeSocket != 0 {
53 c, err := (&net.Dialer{}).DialContext(ctx, "unix", filepath.Join(runtime, name))
54 if err == nil {
55 _ = c.Close()
56 names = append(names, name)
57 }
58 }
59 }
60 if len(names) > 1 {
61 return "", fmt.Errorf("multiple compositor sockets: %v", names)
62 }
63 if len(names) == 1 {
64 return names[0], nil
65 }
66 return "", nil
67}