fix(go.d): correct Windows install paths (#21451)
Ilya Mashchenko committed
Dec 11, 2025 at 19:13 UTC
539f59e41562bfc5bc25fe304c6fd6f6ae79fb6a
2 files changed
+107
-2
src/go/cmd/godplugin/main.go
+1
-1
@@ -60,7 +60,7 @@ func main() {
60
DumpSummary: opts.DumpSummary,
61
})
62
63
- a.Debugf("plugin: name=%s, %s", a.Name, buildinfo.Info())
63
+ a.Infof("plugin: name=%s, %s", a.Name, buildinfo.Info())
64
if u, err := user.Current(); err == nil {
65
a.Debugf("current user: name=%s, uid=%s", u.Username, u.Uid)
66
}
src/go/pkg/buildinfo/buildinfo.go
+106
-1
@@ -2,7 +2,14 @@
2
3
package buildinfo
4
5
-import "fmt"
5
+import (
6
+ "fmt"
7
+ "path/filepath"
8
+ "runtime"
9
+ "strings"
10
+
11
+ "github.com/netdata/netdata/go/plugins/pkg/executable"
12
+)
13
14
// The following variables are set at build time using linker flags.
15
@@ -32,3 +39,101 @@ func Info() string {
39
NetdataBinDir,
40
)
41
}
42
+
43
+func init() {
44
+ if runtime.GOOS != "windows" {
45
+ return
46
+ }
47
+
48
+ execDir := executable.Directory
49
+ if execDir == "" || PluginsDir == "" {
50
+ return
51
+ }
52
+
53
+ // ----------------------------------------------------------------------------
54
+ // 1. Detect install prefix on Windows
55
+ //
56
+ // We assume that on Windows the *running binary* lives inside PluginsDir.
57
+ //
58
+ // Example:
59
+ // execDir = "C:/Program Files/Netdata/usr/libexec/netdata/plugins.d"
60
+ // PluginsDir = "/usr/libexec/netdata/plugins.d"
61
+ //
62
+ // By normalizing both paths to forward-slash format, we can test:
63
+ //
64
+ // strings.HasSuffix(execDir, PluginsDir) → true
65
+ //
66
+ // From that, we strip the suffix and recover the actual installation prefix:
67
+ //
68
+ // prefix = "C:/Program Files/Netdata"
69
+ //
70
+ // If execDir does *not* end with PluginsDir, we simply do nothing — this keeps
71
+ // development/testing environments safe where binaries are run outside the
72
+ // expected layout.
73
+ // ----------------------------------------------------------------------------
74
+ normalized := filepath.ToSlash(execDir)
75
+ suffix := filepath.ToSlash(PluginsDir)
76
+
77
+ if !strings.HasSuffix(normalized, suffix) {
78
+ return
79
+ }
80
+
81
+ // Extract the prefix by removing the suffix.
82
+ //
83
+ // Example:
84
+ // normalized = "C:/Program Files/Netdata/usr/libexec/netdata/plugins.d"
85
+ // suffix = "/usr/libexec/netdata/plugins.d"
86
+ //
87
+ // → prefix = "C:/Program Files/Netdata"
88
+ prefix := strings.TrimSuffix(normalized, suffix)
89
+ prefix = strings.TrimSuffix(prefix, "/")
90
+
91
+ installPrefix := filepath.FromSlash(prefix)
92
+
93
+ // ----------------------------------------------------------------------------
94
+ // 2. Rewrite all buildinfo paths as:
95
+ // <installPrefix> + <original buildinfo path as relative suffix>
96
+ //
97
+ // Example:
98
+ // NetdataBinDir build-time: "/usr/sbin"
99
+ // After rewrite:
100
+ // "C:\Program Files\Netdata\usr\sbin"
101
+ //
102
+ // Notes:
103
+ // • We must remove the *leading slash* from the build-time path, otherwise
104
+ // filepath.Join would treat it as absolute and ignore the prefix.
105
+ //
106
+ // Example of what we avoid:
107
+ // filepath.Join("C:\\Program Files\\Netdata", "/usr/sbin") →
108
+ // "\usr\sbin" (WRONG — prefix lost!)
109
+ //
110
+ // • Paths that were empty at build time should remain empty.
111
+ // ----------------------------------------------------------------------------
112
+ rebuild := func(p string) string {
113
+ if p == "" {
114
+ return ""
115
+ }
116
+
117
+ // Convert to slash form and trim the leading '/' so it becomes relative.
118
+ //
119
+ // Example:
120
+ // p = "/usr/sbin"
121
+ // → s = "usr/sbin"
122
+ //
123
+ s := filepath.ToSlash(p)
124
+ s = strings.TrimPrefix(s, "/")
125
+
126
+ // Now prefix + relative suffix works reliably on Windows.
127
+ //
128
+ // Example:
129
+ // installPrefix = "C:\\Program Files\\Netdata"
130
+ // s = "usr/sbin"
131
+ // → result = "C:\\Program Files\\Netdata\\usr\\sbin"
132
+ return filepath.Join(installPrefix, s)
133
+ }
134
+
135
+ UserConfigDir = rebuild(UserConfigDir)
136
+ StockConfigDir = rebuild(StockConfigDir)
137
+ PluginsDir = rebuild(PluginsDir)
138
+ NetdataBinDir = rebuild(NetdataBinDir)
139
+}