master
go 151 lines 4.43 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package buildinfo
4
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
16 // Version is the Netdata Agent version.
17 var Version = "v0.0.0"
18
19 // UserConfigDir is the path to the user configuration directory.
20 var UserConfigDir = ""
21
22 // StockConfigDir is the path to the stock (default) configuration directory.
23 var StockConfigDir = ""
24
25 // PluginsDir is the path to the installed plugins directory.
26 var PluginsDir = "/usr/libexec/netdata/plugins.d"
27
28 // NetdataBinDir is the path to the installed executables directory.
29 var NetdataBinDir = "/usr/sbin"
30
31 // CacheDir is the path to the Netdata cache directory.
32 var CacheDir = "/var/cache/netdata"
33
34 // Info returns all build information as a single line of space-delimited
35 // key=value pairs using snake_case keys.
36 //
37 // This output is intended for external consumption. Callers must not assume a
38 // fixed set, order, or count of keys. New keys may be added over time as more
39 // build metadata becomes available, so parsers should ignore unknown keys to
40 // remain forward-compatible.
41 func Info() string {
42 return fmt.Sprintf(
43 "version=%s go_version=%s user_config_dir=%s stock_config_dir=%s plugins_dir=%s netdata_bin_dir=%s cache_dir=%s",
44 Version,
45 runtime.Version(),
46 UserConfigDir,
47 StockConfigDir,
48 PluginsDir,
49 NetdataBinDir,
50 CacheDir,
51 )
52 }
53
54 func init() {
55 if runtime.GOOS != "windows" {
56 return
57 }
58
59 execDir := executable.Directory
60 if execDir == "" || PluginsDir == "" {
61 return
62 }
63
64 // ----------------------------------------------------------------------------
65 // 1. Detect install prefix on Windows
66 //
67 // We assume that on Windows the *running binary* lives inside PluginsDir.
68 //
69 // Example:
70 // execDir = "C:/Program Files/Netdata/usr/libexec/netdata/plugins.d"
71 // PluginsDir = "/usr/libexec/netdata/plugins.d"
72 //
73 // By normalizing both paths to forward-slash format, we can test:
74 //
75 // strings.HasSuffix(execDir, PluginsDir) → true
76 //
77 // From that, we strip the suffix and recover the actual installation prefix:
78 //
79 // prefix = "C:/Program Files/Netdata"
80 //
81 // If execDir does *not* end with PluginsDir, we simply do nothing — this keeps
82 // development/testing environments safe where binaries are run outside the
83 // expected layout.
84 // ----------------------------------------------------------------------------
85 normalized := filepath.ToSlash(execDir)
86 suffix := filepath.ToSlash(PluginsDir)
87
88 if !strings.HasSuffix(normalized, suffix) {
89 return
90 }
91
92 // Extract the prefix by removing the suffix.
93 //
94 // Example:
95 // normalized = "C:/Program Files/Netdata/usr/libexec/netdata/plugins.d"
96 // suffix = "/usr/libexec/netdata/plugins.d"
97 //
98 // → prefix = "C:/Program Files/Netdata"
99 prefix := strings.TrimSuffix(normalized, suffix)
100 prefix = strings.TrimSuffix(prefix, "/")
101
102 installPrefix := filepath.FromSlash(prefix)
103
104 // ----------------------------------------------------------------------------
105 // 2. Rewrite all buildinfo paths as:
106 // <installPrefix> + <original buildinfo path as relative suffix>
107 //
108 // Example:
109 // NetdataBinDir build-time: "/usr/sbin"
110 // After rewrite:
111 // "C:\Program Files\Netdata\usr\sbin"
112 //
113 // Notes:
114 // • We must remove the *leading slash* from the build-time path, otherwise
115 // filepath.Join would treat it as absolute and ignore the prefix.
116 //
117 // Example of what we avoid:
118 // filepath.Join("C:\\Program Files\\Netdata", "/usr/sbin") →
119 // "\usr\sbin" (WRONG — prefix lost!)
120 //
121 // • Paths that were empty at build time should remain empty.
122 // ----------------------------------------------------------------------------
123 rebuild := func(p string) string {
124 if p == "" {
125 return ""
126 }
127
128 // Convert to slash form and trim the leading '/' so it becomes relative.
129 //
130 // Example:
131 // p = "/usr/sbin"
132 // → s = "usr/sbin"
133 //
134 s := filepath.ToSlash(p)
135 s = strings.TrimPrefix(s, "/")
136
137 // Now prefix + relative suffix works reliably on Windows.
138 //
139 // Example:
140 // installPrefix = "C:\\Program Files\\Netdata"
141 // s = "usr/sbin"
142 // → result = "C:\\Program Files\\Netdata\\usr\\sbin"
143 return filepath.Join(installPrefix, s)
144 }
145
146 UserConfigDir = rebuild(UserConfigDir)
147 StockConfigDir = rebuild(StockConfigDir)
148 PluginsDir = rebuild(PluginsDir)
149 NetdataBinDir = rebuild(NetdataBinDir)
150 CacheDir = rebuild(CacheDir)
151 }