daemon status 25 (#20026)
added DMI HW information (anonymous - no serial numbers)
Costa Tsaousis committed
Apr 1, 2025 at 21:42 UTC
82f668106e6b11af6759d66271300b8fb036e614
2 files changed
+255
-1
src/daemon/status-file.c
+222
@@ -84,6 +84,144 @@ static void set_stack_trace_message_if_empty(DAEMON_STATUS_FILE *ds, const char
84
strncpyz(ds->fatal.stack_trace, msg, sizeof(ds->fatal.stack_trace) - 1);
85
}
86
87
+// --------------------------------------------------------------------------------------------------------------------
88
+// DMI data
89
+
90
+static void dmi_info(const char *file, const char *alt, char *dst, size_t dst_size) {
91
+ char filename[FILENAME_MAX];
92
+
93
+ if(netdata_configured_host_prefix && *netdata_configured_host_prefix) {
94
+ snprintfz(filename, sizeof(filename), "%s/sys/class/dmi/id/%s", netdata_configured_host_prefix, file);
95
+ if(access(filename, R_OK) != 0) {
96
+ snprintfz(filename, sizeof(filename), "%s/sys/devices/virtual/dmi/id/%s", netdata_configured_host_prefix, file);
97
+ if (access(filename, R_OK) != 0)
98
+ filename[0] = '\0';
99
+ }
100
+ }
101
+ else
102
+ filename[0] = '\0';
103
+
104
+ if(!filename[0]) {
105
+ snprintfz(filename, sizeof(filename), "/sys/class/dmi/id/%s", file);
106
+ if (access(filename, R_OK) != 0) {
107
+ snprintfz(filename, sizeof(filename), "/sys/devices/virtual/dmi/id/%s", file);
108
+ if (access(filename, R_OK) != 0) {
109
+ if (alt && *alt) {
110
+ strncpyz(filename, alt, sizeof(filename) - 1);
111
+ if (access(filename, R_OK) != 0)
112
+ filename[0] = '\0';
113
+ }
114
+ else
115
+ filename[0] = '\0';
116
+ }
117
+ }
118
+ }
119
+
120
+ if(!filename[0]) {
121
+ dst[0] = '\0';
122
+ return;
123
+ }
124
+
125
+ if(read_txt_file(filename, dst, dst_size) != 0) {
126
+ dst[0] = '\0';
127
+ return;
128
+ }
129
+
130
+ char *s = trim_all(dst);
131
+ if(s != dst)
132
+ memmove(dst, s, strlen(s) + 1);
133
+
134
+ struct {
135
+ const char *found;
136
+ const char *replace;
137
+ } replacements[] = {
138
+ {"Default string", ""},
139
+ {"To be filled by O.E.M.", ""},
140
+ {"x.x", ""},
141
+ {"System Product Name", ""},
142
+ {"System Version", ""},
143
+ {"System UUID", ""},
144
+ };
145
+
146
+ for(size_t i = 0; i < _countof(replacements) ;i++) {
147
+ if(strcasecmp(dst, replacements[i].found) == 0) {
148
+ strncpyz(dst, replacements[i].replace, dst_size - 1);
149
+ break;
150
+ }
151
+ }
152
+}
153
+
154
+static void fill_dmi_info(DAEMON_STATUS_FILE *ds) {
155
+ dmi_info("sys_vendor", NULL, ds->hw.sys.vendor, sizeof(ds->hw.sys.vendor));
156
+
157
+ dmi_info("product_name", "/proc/device-tree/model", ds->hw.product.name, sizeof(ds->hw.product.name));
158
+ dmi_info("product_version", NULL, ds->hw.product.version, sizeof(ds->hw.product.version));
159
+ dmi_info("product_sku", NULL, ds->hw.product.sku, sizeof(ds->hw.product.sku));
160
+ dmi_info("product_family", NULL, ds->hw.product.family, sizeof(ds->hw.product.family));
161
+
162
+ dmi_info("chassis_type", NULL, ds->hw.chassis.type, sizeof(ds->hw.chassis.type));
163
+ dmi_info("chassis_vendor", NULL, ds->hw.chassis.vendor, sizeof(ds->hw.chassis.vendor));
164
+ dmi_info("chassis_version", NULL, ds->hw.chassis.version, sizeof(ds->hw.chassis.version));
165
+
166
+ dmi_info("board_vendor", NULL, ds->hw.board.vendor, sizeof(ds->hw.board.vendor));
167
+ dmi_info("board_name", NULL, ds->hw.board.name, sizeof(ds->hw.board.name));
168
+ dmi_info("board_version", NULL, ds->hw.board.version, sizeof(ds->hw.board.version));
169
+
170
+ dmi_info("bios_vendor", NULL, ds->hw.bios.vendor, sizeof(ds->hw.bios.vendor));
171
+ dmi_info("bios_version", NULL, ds->hw.bios.version, sizeof(ds->hw.bios.version));
172
+ dmi_info("bios_date", NULL, ds->hw.bios.date, sizeof(ds->hw.bios.date));
173
+ dmi_info("bios_release", NULL, ds->hw.bios.release, sizeof(ds->hw.bios.release));
174
+
175
+ struct {
176
+ const char *found;
177
+ const char *replace;
178
+ } chassis_types[] = {
179
+ {"1", "other"},
180
+ {"2", "unknown"},
181
+ {"3", "desktop"},
182
+ {"4", "low-profile-desktop"},
183
+ {"5", "pizza-box"},
184
+ {"6", "mini-tower-desktop"},
185
+ {"7", "tower-desktop"},
186
+ {"8", "portable"},
187
+ {"9", "laptop"},
188
+ {"10", "notebook"},
189
+ {"11", "hand-held"},
190
+ {"12", "docking-station"},
191
+ {"13", "all-in-one"},
192
+ {"14", "sub-notebook"},
193
+ {"15", "space-saving-desktop"},
194
+ {"16", "lunch-box"},
195
+ {"17", "main-server-chassis"},
196
+ {"18", "expansion-chassis"},
197
+ {"19", "sub-chassis"},
198
+ {"20", "bus-expansion-chassis"},
199
+ {"21", "peripheral-chassis"},
200
+ {"22", "raid-chassis"},
201
+ {"23", "rack-mount-server"},
202
+ {"24", "sealed-desktop"},
203
+ {"25", "multi-chassis"},
204
+ {"26", "compact-pci"},
205
+ {"27", "advanced-tca"},
206
+ {"28", "blade"},
207
+ {"29", "blade-enclosure"},
208
+ {"30", "tablet"},
209
+ {"31", "convertible"},
210
+ {"32", "detachable"},
211
+ {"33", "iot-gateway"},
212
+ {"34", "embedded-pc"},
213
+ {"35", "mini-pc"},
214
+ {"36", "stick-pc"},
215
+ };
216
+
217
+ for(size_t i = 0; i < _countof(chassis_types) ;i++) {
218
+ if(strcasecmp(ds->hw.chassis.type, chassis_types[i].found) == 0) {
219
+ strncpyz(ds->hw.chassis.type, chassis_types[i].replace, sizeof(ds->hw.chassis.type) - 1);
220
+ break;
221
+ }
222
+ }
223
+}
224
+
225
// --------------------------------------------------------------------------------------------------------------------
226
// json generation
227
@@ -209,6 +347,50 @@ static void daemon_status_file_to_json(BUFFER *wb, DAEMON_STATUS_FILE *ds) {
347
}
348
buffer_json_object_close(wb);
349
350
+ buffer_json_member_add_object(wb, "hw");
351
+ {
352
+ buffer_json_member_add_object(wb, "sys");
353
+ {
354
+ buffer_json_member_add_string(wb, "vendor", ds->hw.sys.vendor);
355
+ }
356
+ buffer_json_object_close(wb);
357
+
358
+ buffer_json_member_add_object(wb, "product");
359
+ {
360
+ buffer_json_member_add_string(wb, "name", ds->hw.product.name);
361
+ buffer_json_member_add_string(wb, "version", ds->hw.product.version);
362
+ buffer_json_member_add_string(wb, "sku", ds->hw.product.sku);
363
+ buffer_json_member_add_string(wb, "family", ds->hw.product.family);
364
+ }
365
+ buffer_json_object_close(wb);
366
+
367
+ buffer_json_member_add_object(wb, "board");
368
+ {
369
+ buffer_json_member_add_string(wb, "name", ds->hw.board.name);
370
+ buffer_json_member_add_string(wb, "version", ds->hw.board.version);
371
+ buffer_json_member_add_string(wb, "vendor", ds->hw.board.vendor);
372
+ }
373
+ buffer_json_object_close(wb);
374
+
375
+ buffer_json_member_add_object(wb, "chassis");
376
+ {
377
+ buffer_json_member_add_string(wb, "type", ds->hw.chassis.type);
378
+ buffer_json_member_add_string(wb, "vendor", ds->hw.chassis.vendor);
379
+ buffer_json_member_add_string(wb, "version", ds->hw.chassis.version);
380
+ }
381
+ buffer_json_object_close(wb);
382
+
383
+ buffer_json_member_add_object(wb, "bios");
384
+ {
385
+ buffer_json_member_add_string(wb, "date", ds->hw.bios.date);
386
+ buffer_json_member_add_string(wb, "release", ds->hw.bios.release);
387
+ buffer_json_member_add_string(wb, "version", ds->hw.bios.version);
388
+ buffer_json_member_add_string(wb, "vendor", ds->hw.bios.vendor);
389
+ }
390
+ buffer_json_object_close(wb);
391
+ }
392
+ buffer_json_object_close(wb);
393
+
394
buffer_json_member_add_object(wb, "fatal");
395
{
396
buffer_json_member_add_uint64(wb, "line", ds->fatal.line);
@@ -276,6 +458,7 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
458
bool required_v22 = version >= 22 ? strict : false;
459
bool required_v23 = version >= 23 ? strict : false;
460
bool required_v24 = version >= 24 ? strict : false;
461
+ bool required_v25 = version >= 25 ? strict : false;
462
463
// Parse timestamp
464
JSONC_PARSE_TXT2RFC3339_USEC_OR_ERROR_AND_RETURN(jobj, path, "@timestamp", ds->timestamp_ut, error, required_v1);
@@ -402,6 +585,39 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
585
JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "platform", ds->os_id_like, error, required_v1);
586
});
587
588
+ // Parse the hw object
589
+ JSONC_PARSE_SUBOBJECT(jobj, path, "hw", error, required_v25, {
590
+ JSONC_PARSE_SUBOBJECT(jobj, path, "sys", error, required_v25, {
591
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "vendor", ds->hw.sys.vendor, error, required_v25);
592
+ });
593
+
594
+ JSONC_PARSE_SUBOBJECT(jobj, path, "product", error, required_v25, {
595
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "name", ds->hw.product.name, error, required_v25);
596
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "version", ds->hw.product.version, error, required_v25);
597
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "sku", ds->hw.product.sku, error, required_v25);
598
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "family", ds->hw.product.family, error, required_v25);
599
+ });
600
+
601
+ JSONC_PARSE_SUBOBJECT(jobj, path, "board", error, required_v25, {
602
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "name", ds->hw.board.name, error, required_v25);
603
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "version", ds->hw.board.version, error, required_v25);
604
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "vendor", ds->hw.board.vendor, error, required_v25);
605
+ });
606
+
607
+ JSONC_PARSE_SUBOBJECT(jobj, path, "chassis", error, required_v25, {
608
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path,"type", ds->hw.chassis.type ,error ,required_v25);
609
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj,path,"vendor" ,ds->hw.chassis.vendor ,error ,required_v25);
610
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj,path,"version" ,ds->hw.chassis.version ,error ,required_v25);
611
+ });
612
+
613
+ JSONC_PARSE_SUBOBJECT(jobj,path,"bios" ,error ,required_v25,{
614
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "date", ds->hw.bios.date, error, required_v25);
615
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "release", ds->hw.bios.release, error, required_v25);
616
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "version", ds->hw.bios.version, error, required_v25);
617
+ JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "vendor", ds->hw.bios.vendor, error, required_v25);
618
+ });
619
+ });
620
+
621
// Parse fatal object
622
JSONC_PARSE_SUBOBJECT(jobj, path, "fatal", error, required_v1, {
623
JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "filename", ds->fatal.filename, error, required_v1);
@@ -507,6 +723,8 @@ static void daemon_status_file_migrate_once(void) {
723
724
strncpyz(session_status.stack_traces, capture_stack_trace_backend(), sizeof(session_status.stack_traces) - 1);
725
726
+ fill_dmi_info(&session_status);
727
+
728
dsf_release(last_session_status);
729
dsf_release(session_status);
730
}
@@ -801,7 +1019,11 @@ static enum crash_report_t check_crash_reports_config(void) {
1019
void daemon_status_file_init(void) {
1020
static_save_buffer_init();
1021
mallocz_register_out_of_memory_cb(daemon_status_file_out_of_memory);
1022
+
1023
status_file_io_load(STATUS_FILENAME, status_file_load_and_parse, &last_session_status);
1024
+ if(last_session_status.v < 25)
1025
+ fill_dmi_info(&last_session_status);
1026
+
1027
daemon_status_file_migrate_once();
1028
}
1029
src/daemon/status-file.h
+33
-1
@@ -9,7 +9,7 @@
9
#include "claim/cloud-status.h"
10
#include "machine-guid.h"
11
12
-#define STATUS_FILE_VERSION 24
12
+#define STATUS_FILE_VERSION 25
13
14
typedef enum {
15
DAEMON_STATUS_NONE,
@@ -87,6 +87,38 @@ typedef struct daemon_status_file {
87
char cloud_instance_region[32];
88
bool read_system_info;
89
90
+ struct {
91
+ struct {
92
+ char vendor[64];
93
+ } sys;
94
+
95
+ struct {
96
+ char name[64];
97
+ char version[64];
98
+ char sku[64];
99
+ char family[64];
100
+ } product;
101
+
102
+ struct {
103
+ char name[64];
104
+ char version[64];
105
+ char vendor[64];
106
+ } board;
107
+
108
+ struct {
109
+ char type[64];
110
+ char vendor[64];
111
+ char version[64];
112
+ } chassis;
113
+
114
+ struct {
115
+ char date[16];
116
+ char release[64];
117
+ char version[64];
118
+ char vendor[64];
119
+ } bios;
120
+ } hw;
121
+
122
char stack_traces[63]; // the backend for capturing stack traces
123
124
struct {