Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
SystemConfiguration.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Common_SystemConfiguration_h_
5#define _Stroika_Foundation_Common_SystemConfiguration_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
10#include "Stroika/Foundation/Common/Common.h"
11#include "Stroika/Foundation/Common/GUID.h"
12#include "Stroika/Foundation/Containers/Sequence.h"
14
15/**
16 * \file
17 *
18 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
19 *
20 * TODO:
21 * @todo Review API provide, and document relationship with sysconf/etc (idea is simpler, and a bit more portable,
22 * but just subset).
23 *
24 * @todo BootInformation: consider adding info like 'last shutdown at' and last shutdown reason.
25 *
26 * @todo BootInformation: simplistic impl - may not handle 'hibernate' properly... - must verify/test, and timezone
27 * change etc... just uses seconds since boot on most platforms??
28 *
29 */
30
32
33 using Characters::String;
34
35 /**
36 * \brief What can be told of the machine this runs on - GetSystemConfiguration () gets it all, each
37 * GetSystemConfiguration_Xxx () a part.
38 *
39 * \note Logging it: ToString () leaves out fMachineID (saying only whether there is one), but code writing the fields out
40 * itself - a serializer, say - must leave it out too (or use GetSystemConfiguration_MachineID (applicationKey) instead).
41 * And even without it, a SystemConfiguration - its host name, operating system, CPU and so on - can identify the
42 * machine: mind where it is written.
43 */
45
46 /**
47 */
48 struct BootInformation {
49 optional<Time::DateTime> fBootedAt;
50
51 /**
52 * @see Characters::ToString ();
53 */
54 nonvirtual String ToString () const;
55 };
56
57 /**
58 */
59 struct CPU {
60 public:
61 /**
62 * Number of Physical Sockets/CPU chips. Also this is the number of distinct 'socket ids' from the fCores.
63 */
64 nonvirtual unsigned int GetNumberOfSockets () const;
65
66 public:
67 /**
68 * Number of Logical Cores (aka max concurrent logical thread count). This will generally be
69 * divisible by fNumberOfSockets.
70 *
71 * @see Common::GetNumberOfLogicalCPUCores
72 */
73 nonvirtual unsigned int GetNumberOfLogicalCores () const;
74
75 public:
76 /**
77 * Each socket will typically have the identical model name. This returns the value from the first.
78 * check each fCore to see if they differ.
79 *
80 * If the fCores is empty, this is safe, and returns an empty string.
81 */
82 nonvirtual String GetCPUModelPrintName () const;
83
84 public:
85 /**
86 * Details we track per CPU (socket/chip). There is much more info in /proc/cpuinfo, like
87 * MHz, and cache size, and particular numerical model numbers. Possibly also add 'bogomips'?
88 */
89 struct CoreDetails {
90 /**
91 * /proc/cpuinfo 'physical id' - use to tell number of sockets. Each distinct socketID is a different socket
92 */
93 unsigned int fSocketID{};
94
95 /**
96 * /proc/cpuinfo 'model name' field - a semi-standardized representation of what you want to know about a CPU chip
97 */
99
100 /**
101 */
102 CoreDetails (unsigned int socketID = {}, const String& modelName = String{});
103
104 /**
105 * @see Characters::ToString ();
106 */
107 nonvirtual String ToString () const;
108 };
109
110 public:
111 /**
112 * A computer may have multiple CPUCores, and in principle they can differ.
113 * The number of filled 'cpu sockets' is fCPUs.length ().
114 *
115 * \note These are 'logical cores' and may not be physical cores.
116 * \note We have no way to capture physical cores (per socket). Not sure that is helpful/needed.
117 */
119
120 public:
121 /**
122 * @see Characters::ToString ();
123 */
124 nonvirtual String ToString () const;
125 };
126
127 /**
128 */
129 struct Memory {
130 /**
131 * Size in bytes
132 */
133 size_t fPageSize{};
134
135 /**
136 * Size in bytes
137 */
138 uint64_t fTotalPhysicalRAM{};
139
140 /**
141 * Size in bytes
142 */
143 uint64_t fTotalVirtualRAM{};
144
145 /**
146 * @see Characters::ToString ();
147 */
148 nonvirtual String ToString () const;
149 };
150
151 /**
152 */
153 struct OperatingSystem {
154 /**
155 * e.g. Linux/MacOS/Windows/Unix (on POSIX systems - value of uname)
156 */
157 String fTokenName;
158
159 /**
160 * e.g. Linux/Ubuntu,RedHat, Windows XP, Windows 2000
161 */
162 String fShortPrettyName;
163
164 /**
165 * e.g. RedHat 3.5, Ubuntu 11, Windows XP, Windows 8, Windows 8.1, Windows 10
166 */
167 String fPrettyNameWithMajorVersion;
168
169 /**
170 * Similar level of detail to what is printed by 'winver' application.
171 *
172 * e.g. Windows 10 Version 1809 (OS Build 17763.379)
173 */
174 String fPrettyNameWithVersionDetails;
175
176 /**
177 * e.g. 1.0, 3.5, etc. Note - this refers to the overall os (distribution -
178 * like for ubuntu 11.04, this would be 11.04, not the kernel version)
179 */
180 String fMajorMinorVersionString;
181
182 /**
183 * http://tools.ietf.org/html/rfc1945#section-10.15
184 * http://tools.ietf.org/html/rfc1945#section-3.7
185 *
186 * e.g. MyProduct/1.0, Mozilla/3.5, etc
187 */
188 String fRFC1945CompatProductTokenWithVersion;
189
190 /**
191 * Number of bits the OS targets. Often a 64-bit OS will support 32-bits, and concievably other
192 * combinations are possible. But this value returns the principle / primary number of bits supported
193 * by the OS (bits of addressing).
194 */
195 unsigned int fBits{32};
196
197 /**
198 *
199 * \note Common::DefaultNames<> supported
200 */
201 enum class InstallerTechnology {
202 eRPM,
203 eMSI,
204 eDPKG,
205
206 Stroika_Define_Enum_Bounds (eRPM, eDPKG)
207 };
208
209 /**
210 * Some UNIX systems use rpm (redhat, and many others), and others use dpkg (Debian based).
211 * Windows uses MSI.
212 * But there are a wide variety of other choices (portage, ports, etc).
213 */
214 optional<InstallerTechnology> fPreferredInstallerTechnology;
215
216 /**
217 * @see Characters::ToString ();
218 */
219 nonvirtual String ToString () const;
220 };
221
222 /**
223 * This is very frequently NOT useful, not unique, but frequently desired/used,
224 * so at least you can get to it uniformly, cross-platform.
225 */
227 /**
228 * Returns the best OS dependent guess at a computer name we have.
229 *
230 * On windows, this amounts to the NETBIOS name, and on UNIX, this amounts
231 * to the result of 'gethostname' (man 2 hostname).
232 */
234
235 /**
236 * @see Characters::ToString ();
237 */
238 nonvirtual String ToString () const;
239 };
240
241 BootInformation fBootInformation;
242 CPU fCPU;
243 Memory fMemory;
244
245 /**
246 * Info about the actual operating system this software is running on (if possible to tell, it could be well hidden)
247 *
248 * Often virtualization (things like compatibility mode in a manifest, or perhaps docker, or WSL) makes the apparent
249 * operating system different than the one you are actually running on).
250 *
251 * \note Actual Operating System is typically what you would report to a user (GUI).
252 */
253 OperatingSystem fActualOperatingSystem;
254
255 /**
256 * Return info about the apparent operating system this software is running on.
257 *
258 * Often virtualization (things like compatibility mode in a manifest, or perhaps docker, or WSL) makes the apparent
259 * operating system different than the one you are actually running on).
260 */
262 ComputerNames fComputerNames;
263
264 /**
265 * The OS's own ID for this machine - @see GetSystemConfiguration_MachineID (). Confidential, so ToString () says only
266 * whether there is one (@see SystemConfiguration's note on logging it).
267 */
268 optional<GUID> fMachineID;
269
270 /**
271 */
272 SystemConfiguration (const BootInformation& bi, const CPU& ci, const Memory& mi, const OperatingSystem& oi, const ComputerNames& cn,
273 const optional<GUID>& machineID = nullopt);
274 SystemConfiguration (const BootInformation& bi, const CPU& ci, const Memory& mi, const OperatingSystem& actualOS,
275 const OperatingSystem& apparentOS, const ComputerNames& cn, const optional<GUID>& machineID = nullopt);
276
277 /**
278 * \note Leaves out fMachineID - saying only whether there is one - so tracing a whole SystemConfiguration is safe. How
279 * to keep it (and other identifying data) out of logs and serialized copies more generally:
280 * https://github.com/SophistSolutions/Stroika/issues/1196
281 *
282 * @see Characters::ToString ();
283 */
284 nonvirtual String ToString () const;
285 };
286
287 /**
288 * @brief Get the System Configuration object - note not a system global - because the configuration can change while the app is running
289 *
290 * @return SystemConfiguration
291 */
293
294 /**
295 */
296 SystemConfiguration::BootInformation GetSystemConfiguration_BootInformation ();
297
298 /**
299 */
300 SystemConfiguration::CPU GetSystemConfiguration_CPU ();
301
302 /**
303 */
304 SystemConfiguration::Memory GetSystemConfiguration_Memory ();
305
306 /**
307 * Return info about the actual operating system this software is running on (if possible to tell, it could be well hidden)
308 *
309 * Often virtualization (things like compatability mode in a manifest, or perhaps docker, or WSL) makes the apprarent
310 * operating system different than the one you are actually running on).
311 */
312 SystemConfiguration::OperatingSystem GetSystemConfiguration_ActualOperatingSystem ();
313
314 /**
315 * Return info about the apparent operating system this software is running on.
316 *
317 * Often virtualization (things like compatability mode in a manifest, or perhaps docker, or WSL) makes the apprarent
318 * operating system different than the one you are actually running on).
319 */
320 SystemConfiguration::OperatingSystem GetSystemConfiguration_ApparentOperatingSystem ();
321
322 /**
323 */
324 SystemConfiguration::ComputerNames GetSystemConfiguration_ComputerNames ();
325
326 /**
327 * \brief The operating system's own ID for this machine - exactly as the OS keeps it, the same every time (it survives
328 * reboots); nullopt if the OS has none, or it cannot be read.
329 *
330 * Each OS supported keeps a 128-bit ID for the machine, returned unaltered - its text (As<String> ()) is the OS's own, but
331 * for case and dashes:
332 * Linux: /etc/machine-id (else /var/lib/dbus/machine-id) - made when the OS is installed: by systemd, a random
333 * UUID; by older tools, 128 random bits, not always marked as a UUID
334 * Windows: the registry's MachineGuid (HKEY_LOCAL_MACHINE, under SOFTWARE, Microsoft, Cryptography) - a GUID made
335 * when the OS is installed
336 * macOS: gethostuuid () - the hardware's UUID (as IOPlatformUUID), so it survives a reinstall
337 * Others: nullopt for now. A platform supported later (a BSD, say) returns its own ID, unaltered, where it keeps
338 * one; where it does not, its entry here will say what is returned instead (perhaps derived from what it
339 * does keep) - or nullopt.
340 *
341 * The applicationKey overload returns not the OS's ID but one DERIVED from it, for that application: a name-based UUID
342 * (RFC 9562 version 3 - the MD5 of applicationKey and the machine's ID). So it is the same each time for that application
343 * on this machine, and different for another application, or machine - and does not reveal the machine's own ID (nullopt
344 * where that is).
345 *
346 * \note Not a promise of uniqueness: a cloned virtual machine (or a Windows image not sysprepped) has its original's ID,
347 * and a container may have none - or share its image's.
348 *
349 * \note Treat it as confidential: systemd's docs say not to expose it on a network. For an ID that leaves the machine
350 * (a UPnP device ID, say), derive one for your application with the applicationKey overload.
351 *
352 * \par Example Usage
353 * \code
354 * // a UPnP device ID - the same each time, and different on another machine (as UPnP requires)
355 * static const Common::GUID kMyProduct_{"315CAAE0-1335-57BF-A178-24C9EE756627"sv};
356 * if (optional<Common::GUID> id = Common::GetSystemConfiguration_MachineID (kMyProduct_)) {
357 * device.fDeviceID = *id;
358 * }
359 * \endcode
360 */
361 optional<GUID> GetSystemConfiguration_MachineID ();
362 optional<GUID> GetSystemConfiguration_MachineID (const GUID& applicationKey); ///< \brief one derived for an application
363
364 /**
365 * \brief return the number of currently available CPU cores on this (virtual) machine
366 *
367 * This is very roughly GetSystemConfiguration_CPU ().GetNumberOfLogicalCores ()
368 * BUT - this CAN CHANGE over time, and this routine tries to provide a QUICK (cheap so not 100% guaranteed right) answer
369 * but generally will be quicker than GetSystemConfiguration_CPU ().GetNumberOfLogicalCores (), and provides
370 * stronger guaranteeds about accurance than std::thread::hardware_concurrency (https://en.cppreference.com/w/cpp/thread/thread/hardware_concurrency)
371 *
372 * @see GetSystemConfiguration_CPU
373 * @see SystemConfiguration::CPU::GetNumberOfLogicalCores
374 */
375 unsigned int GetNumberOfLogicalCPUCores (const chrono::duration<double>& allowedStaleness = 1min);
376
377}
378
379/*
380 ********************************************************************************
381 ***************************** Implementation Details ***************************
382 ********************************************************************************
383 */
384#include "SystemConfiguration.inl"
385
386#endif /*_Stroika_Foundation_Common_SystemConfiguration_h_*/
#define Stroika_Define_Enum_Bounds(FIRST_ITEM, LAST_ITEM)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A generalization of a vector: a container whose elements are keyed by the natural numbers.
STRING_TYPE ToString(FLOAT_TYPE f, const ToStringOptions &options={})
SystemConfiguration::OperatingSystem GetSystemConfiguration_ActualOperatingSystem()
SystemConfiguration GetSystemConfiguration()
Get the System Configuration object - note not a system global - because the configuration can change...
optional< GUID > GetSystemConfiguration_MachineID()
The operating system's own ID for this machine - exactly as the OS keeps it, the same every time (it ...
SystemConfiguration::OperatingSystem GetSystemConfiguration_ApparentOperatingSystem()
unsigned int GetNumberOfLogicalCPUCores(const chrono::duration< double > &allowedStaleness=1min)
return the number of currently available CPU cores on this (virtual) machine
What can be told of the machine this runs on - GetSystemConfiguration () gets it all,...