/src/wireshark/wsutil/version_info.c
Line | Count | Source |
1 | | /* version_info.c |
2 | | * Routines to report version information for Wireshark programs |
3 | | * |
4 | | * Wireshark - Network traffic analyzer |
5 | | * By Gerald Combs <gerald@wireshark.org> |
6 | | * Copyright 1998 Gerald Combs |
7 | | * |
8 | | * SPDX-License-Identifier: GPL-2.0-or-later |
9 | | */ |
10 | | |
11 | | #include <config.h> |
12 | | #include "version_info.h" |
13 | | |
14 | | #include <stdio.h> |
15 | | #include <string.h> |
16 | | #include <locale.h> |
17 | | |
18 | | #ifdef _WIN32 |
19 | | #include <windows.h> |
20 | | #elif __APPLE__ |
21 | | #include <sys/types.h> |
22 | | #include <sys/sysctl.h> |
23 | | #elif __linux__ |
24 | | #include <sys/sysinfo.h> |
25 | | #endif |
26 | | |
27 | | #include <glib.h> |
28 | | #include <gmodule.h> |
29 | | #include <pcre2.h> |
30 | | |
31 | | #ifdef HAVE_XXHASH |
32 | | #include <xxhash.h> |
33 | | #endif |
34 | | |
35 | | #ifdef HAVE_ZLIB |
36 | | #include <zlib.h> |
37 | | #endif |
38 | | |
39 | | //#ifdef HAVE_ZLIBNG |
40 | | //#include <zlib-ng.h> |
41 | | //#endif |
42 | | |
43 | | #include <wsutil/cpu_info.h> |
44 | | #include <wsutil/os_version_info.h> |
45 | | #include <wsutil/crash_info.h> |
46 | | #include <wsutil/plugins.h> |
47 | | |
48 | | static char *appname_with_version; |
49 | | static char *copyright_info; |
50 | | static char *license_info; |
51 | | static char *comp_info; |
52 | | static char *runtime_info; |
53 | | |
54 | | static void end_string(GString *str); |
55 | | static void get_compiler_info(GString *str); |
56 | | static void get_mem_info(GString *str); |
57 | | |
58 | | void |
59 | | ws_init_version_info(const char *appname, |
60 | | const char* appflavor, |
61 | | get_version_func version_func, |
62 | | gather_feature_func gather_compile, |
63 | | gather_feature_func gather_runtime) |
64 | 15 | { |
65 | 15 | GString *comp_info_str, *runtime_info_str; |
66 | 15 | GString *copyright_info_str; |
67 | 15 | GString *license_info_str; |
68 | | |
69 | 15 | copyright_info_str = g_string_new(get_copyright_info()); |
70 | 15 | end_string(copyright_info_str); |
71 | 15 | copyright_info = g_string_free(copyright_info_str, FALSE); |
72 | | |
73 | 15 | license_info_str = g_string_new(get_license_info_short()); |
74 | 15 | end_string(license_info_str); |
75 | 15 | license_info = g_string_free(license_info_str, FALSE); |
76 | | |
77 | | /* |
78 | | * Combine the supplied application name string with the |
79 | | * version - including the VCS version, for a build from |
80 | | * a checkout. |
81 | | */ |
82 | 15 | if ((appflavor != NULL) && strstr(appname, appflavor) != NULL) { |
83 | 0 | appname_with_version = ws_strdup_printf("%s %s", |
84 | 0 | appname, version_func()); |
85 | 0 | } |
86 | | /* Include our application flavor. The default is "Wireshark" */ |
87 | 15 | else { |
88 | 15 | appname_with_version = ws_strdup_printf("%s (%s) %s", |
89 | 15 | appname, (appflavor != NULL) ? appflavor : "Wireshark", version_func()); |
90 | 15 | } |
91 | | |
92 | | /* Get the compile-time version information string */ |
93 | 15 | comp_info_str = get_compiled_version_info(gather_compile); |
94 | | |
95 | | /* Get the run-time version information string */ |
96 | 15 | runtime_info_str = get_runtime_version_info(gather_runtime); |
97 | | |
98 | 15 | comp_info = g_string_free(comp_info_str, FALSE); |
99 | 15 | runtime_info = g_string_free(runtime_info_str, FALSE); |
100 | | |
101 | | /* Add this information to the information to be reported on a crash. */ |
102 | 15 | ws_add_crash_info("%s\n" |
103 | 15 | "\n" |
104 | 15 | "%s\n" |
105 | 15 | "%s", |
106 | 15 | appname_with_version, comp_info, runtime_info); |
107 | 15 | } |
108 | | |
109 | | /* |
110 | | * Used below in features_to_columns() |
111 | | */ |
112 | | static void |
113 | | rtrim_gstring(GString *str) |
114 | 105 | { |
115 | 105 | size_t end = str->len - 1; // get to 0-based offset |
116 | 810 | while(str->str[end] == ' ') { |
117 | 705 | end--; |
118 | 705 | } |
119 | 105 | end++; // return to 1-based length |
120 | 105 | if (end < str->len) { |
121 | 105 | g_string_truncate(str, end); |
122 | 105 | } |
123 | 105 | } |
124 | | |
125 | | /* |
126 | | * Take the list of features, and format it into a number of vertical |
127 | | * columns, presented in column-major order. Calculates the number of |
128 | | * columns based on the length of the longest list item. |
129 | | */ |
130 | | static void |
131 | | features_to_columns(feature_list l, GString *str) |
132 | 45 | { |
133 | 45 | const uint8_t linelen = 85; // Same value used in end_string() +10 |
134 | 45 | const uint8_t linepad = 2; // left-side padding |
135 | 45 | uint8_t ncols = 0; // number of columns to show |
136 | 45 | uint8_t maxlen = 0; // length of longest item |
137 | 45 | unsigned num = 0; // number of items in list |
138 | 45 | char *c; |
139 | 45 | GPtrArray *a; |
140 | 45 | GList *iter; |
141 | | |
142 | 45 | num = g_list_length(*l); |
143 | 45 | if (num == 0) { |
144 | 0 | return; |
145 | 0 | } |
146 | 45 | a = g_ptr_array_sized_new(num); |
147 | 360 | for (iter = *l; iter != NULL; iter = iter->next) { |
148 | 315 | c = (char *)iter->data; |
149 | 315 | maxlen = MAX(maxlen, (uint8_t)strlen(c)); |
150 | 315 | g_ptr_array_add(a, iter->data); |
151 | 315 | } |
152 | 45 | maxlen += 2; // allow space between columns |
153 | 45 | ncols = (linelen - linepad) / maxlen; |
154 | 45 | if (ncols <= 1 || num <= 1) { |
155 | 0 | for (iter = *l; iter != NULL; iter = iter->next) { |
156 | 0 | c = (char *)iter->data; |
157 | 0 | g_string_append_printf(str, "%*s%s\n", linepad, "", c); |
158 | 0 | } |
159 | 0 | } |
160 | 45 | else { |
161 | 45 | uint8_t nrows = (num + ncols - 1) / ncols; |
162 | 45 | unsigned i, j; |
163 | 150 | for (i = 0; i < nrows; i++) { |
164 | 105 | g_string_append_printf(str, "%*s", linepad, ""); |
165 | 555 | for (j = 0; j < ncols; j++) { |
166 | 450 | unsigned idx = i + (j * nrows); |
167 | 450 | if (idx < num) { |
168 | 315 | g_string_append_printf(str, "%-*s", maxlen, (char *)g_ptr_array_index(a, idx)); |
169 | 315 | } |
170 | 450 | } |
171 | 105 | rtrim_gstring(str); |
172 | 105 | g_string_append(str, "\n"); |
173 | 105 | } |
174 | 45 | } |
175 | 45 | g_ptr_array_free(a, TRUE); |
176 | 45 | } |
177 | | |
178 | | /* |
179 | | * If the string doesn't end with a newline, append one. |
180 | | * Then word-wrap it to 80 columns. |
181 | | */ |
182 | | static void |
183 | | end_string(GString *str) |
184 | 60 | { |
185 | 60 | size_t point; |
186 | 60 | char *p, *q; |
187 | | |
188 | 60 | point = str->len; |
189 | 60 | if (point == 0 || str->str[point - 1] != '\n') |
190 | 60 | g_string_append(str, "\n"); |
191 | 60 | p = str->str; |
192 | 450 | while (*p != '\0') { |
193 | 390 | q = strchr(p, '\n'); |
194 | 390 | if (q - p > 80) { |
195 | | /* |
196 | | * Break at or before this point. |
197 | | */ |
198 | 45 | q = p + 80; |
199 | 225 | while (q > p && *q != ' ') |
200 | 180 | q--; |
201 | 45 | if (q != p) |
202 | 45 | *q = '\n'; |
203 | 45 | } |
204 | 390 | p = q + 1; |
205 | 390 | } |
206 | 60 | } |
207 | | |
208 | | const char * |
209 | | get_appname_and_version(void) |
210 | 0 | { |
211 | 0 | return appname_with_version; |
212 | 0 | } |
213 | | |
214 | | void |
215 | | gather_pcre2_compile_info(feature_list l) |
216 | 15 | { |
217 | 15 | #define PCRE2_DATE_QUOTE(str) #str |
218 | 15 | #define PCRE2_DATE_EXPAND_AND_QUOTE(str) PCRE2_DATE_QUOTE(str) |
219 | | /* |
220 | | * PCRE2_PRERELEASE appears to be empty for a regular release; |
221 | | * I don't know what it is for a pre-release. |
222 | | */ |
223 | 15 | with_feature(l, "PCRE2 %u.%u %s", PCRE2_MAJOR, PCRE2_MINOR, PCRE2_DATE_EXPAND_AND_QUOTE(PCRE2_DATE)); |
224 | 15 | } |
225 | | |
226 | | void |
227 | | gather_xxhash_compile_info(feature_list l) |
228 | 15 | { |
229 | | #ifdef HAVE_XXHASH |
230 | | with_feature(l, "xxhash " XXHASH_VERSION_STRING); |
231 | | #else |
232 | 15 | without_feature(l, "xxhash"); |
233 | 15 | #endif /* HAVE_XXHASH */ |
234 | 15 | } |
235 | | |
236 | | void |
237 | | gather_zlib_compile_info(feature_list l) |
238 | 15 | { |
239 | 15 | #ifdef HAVE_ZLIB |
240 | 15 | #ifdef ZLIB_VERSION |
241 | 15 | with_feature(l, "zlib " ZLIB_VERSION); |
242 | | #else |
243 | | with_feature(l, "zlib (version unknown)"); |
244 | | #endif /* ZLIB_VERSION */ |
245 | | #else |
246 | | without_feature(l, "zlib"); |
247 | | #endif /* HAVE_ZLIB */ |
248 | 15 | } |
249 | | |
250 | | void |
251 | | gather_zlib_ng_compile_info(feature_list l) |
252 | 15 | { |
253 | | #ifdef HAVE_ZLIBNG |
254 | | with_feature(l, "zlib-ng " ZLIBNG_VERSION_STRING); |
255 | | #else |
256 | 15 | without_feature(l, "zlib-ng"); |
257 | 15 | #endif /* HAVE_ZLIB */ |
258 | 15 | } |
259 | | |
260 | | |
261 | | /* |
262 | | * Get various library compile-time versions, put them in a GString, |
263 | | * and return the GString. |
264 | | */ |
265 | | GString * |
266 | | get_compiled_version_info(gather_feature_func gather_compile) |
267 | 15 | { |
268 | 15 | GString *str; |
269 | 15 | GList *l = NULL, *with_list = NULL, *without_list = NULL; |
270 | | |
271 | 15 | str = g_string_new("Compile-time info:\n"); |
272 | 15 | g_string_append_printf(str, " Bit width: %d-bit\n", (int)sizeof(str) * 8); |
273 | | |
274 | | /* Compiler info */ |
275 | 15 | g_string_append_printf(str, " Compiler: "); |
276 | 15 | get_compiler_info(str); |
277 | | |
278 | 15 | #ifdef GLIB_MAJOR_VERSION |
279 | 15 | g_string_append_printf(str, |
280 | 15 | " GLib: %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, |
281 | 15 | GLIB_MICRO_VERSION); |
282 | | #else |
283 | | g_string_append(str, " GLib: version unknown"); |
284 | | #endif |
285 | | #ifdef WS_DISABLE_DEBUG |
286 | | g_string_append(str, ", release build"); |
287 | | #endif |
288 | | #ifdef WS_DISABLE_ASSERT |
289 | | g_string_append(str, ", without assertions"); |
290 | | #endif |
291 | 15 | g_string_append(str, "\n"); |
292 | | |
293 | 15 | if (gather_compile != NULL) { |
294 | 15 | gather_compile(&l); |
295 | 15 | } |
296 | | |
297 | 15 | sort_features(&l); |
298 | 15 | separate_features(&l, &with_list, &without_list); |
299 | 15 | free_features(&l); |
300 | | |
301 | 15 | if (with_list != NULL) { |
302 | 15 | g_string_append(str, " With:\n"); |
303 | 15 | features_to_columns(&with_list, str); |
304 | 15 | free_features(&with_list); |
305 | 15 | } |
306 | 15 | if (without_list != NULL) { |
307 | 15 | g_string_append(str, " Without:\n"); |
308 | 15 | features_to_columns(&without_list, str); |
309 | 15 | free_features(&without_list); |
310 | 15 | } |
311 | | |
312 | 15 | end_string(str); |
313 | 15 | return str; |
314 | 15 | } |
315 | | |
316 | | static void |
317 | | get_mem_info(GString *str) |
318 | 15 | { |
319 | 15 | int64_t memsize = 0; |
320 | | |
321 | | #ifdef _WIN32 |
322 | | MEMORYSTATUSEX statex; |
323 | | |
324 | | statex.dwLength = sizeof (statex); |
325 | | |
326 | | if (GlobalMemoryStatusEx(&statex)) |
327 | | memsize = statex.ullTotalPhys; |
328 | | #elif __APPLE__ |
329 | | size_t len = sizeof(memsize); |
330 | | sysctlbyname("hw.memsize", &memsize, &len, NULL, 0); |
331 | | #elif __linux__ |
332 | | struct sysinfo info; |
333 | 15 | if (sysinfo(&info) == 0) |
334 | 15 | if (ckd_mul(&memsize, info.totalram, info.mem_unit)) |
335 | 0 | memsize = 0; |
336 | 15 | #endif |
337 | | |
338 | 15 | if (memsize > 0) |
339 | 15 | g_string_append_printf(str, "%" PRId64 " MB of physical memory", memsize/(1024*1024)); |
340 | 15 | } |
341 | | |
342 | | /* |
343 | | * Get compiler information, and append it to the GString. |
344 | | */ |
345 | | static void |
346 | | get_compiler_info(GString *str) |
347 | 15 | { |
348 | | /* |
349 | | * See https://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers |
350 | | * information on various defined strings. |
351 | | * |
352 | | * GCC's __VERSION__ is a nice text string for humans to |
353 | | * read. The page at sourceforge.net largely describes |
354 | | * numeric #defines that encode the version; if the compiler |
355 | | * doesn't also offer a nice printable string, we try prettifying |
356 | | * the number somehow. |
357 | | */ |
358 | | #if defined(_MSC_FULL_VER) |
359 | | /* |
360 | | * We check for this first, as Microsoft have a version of their |
361 | | * compiler that has Clang as the front end and their code generator |
362 | | * as the back end. |
363 | | * |
364 | | * My head asplode. |
365 | | */ |
366 | | |
367 | | /* As of Wireshark 3.0, we support only Visual Studio 2015 (14.x) |
368 | | * or later. |
369 | | * |
370 | | * https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd |
371 | | * has a *large* table of Microsoft product names, VC++ versions, |
372 | | * _MSC_VER values, and _MSC_FULL_VER values. All the versions |
373 | | * we support define _MSC_FULL_VER. We don't bother trying to |
374 | | * get the SP/update/version number from the build number, as |
375 | | * we'd have to keep updating that with every update; there's no |
376 | | * way to get that information directly from a predefine, and in |
377 | | * some cases multiple updates/versions have the *same* build |
378 | | * number (because they didn't update the toolchain). |
379 | | * |
380 | | * https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2017 |
381 | | * defines the format of _MSC_VER and _MSC_FULL_VER. _MSC_FULL_VER |
382 | | * is a decimal number of the form MMmmBBBBB, where MM is the compiler/ |
383 | | * toolchain major version, mm is the minor version, and BBBBB is the |
384 | | * build. We break it down based on that. |
385 | | */ |
386 | | #define COMPILER_MAJOR_VERSION (_MSC_FULL_VER / 10000000) |
387 | | #define COMPILER_MINOR_VERSION ((_MSC_FULL_VER % 10000000) / 100000) |
388 | | #define COMPILER_BUILD_NUMBER (_MSC_FULL_VER % 100000) |
389 | | |
390 | | /* |
391 | | * From https://web.archive.org/web/20190125151548/https://blogs.msdn.microsoft.com/vcblog/2014/11/17/c111417-features-in-vs-2015-preview/ |
392 | | * Bakersfield: DevDiv's upper management determines the scheduling |
393 | | * of new major versions. They also decided to increment the product |
394 | | * version from 12 (for VS 2013) to 14 (for VS 2015). However, the |
395 | | * C++ compiler's version incremented normally, from 18 to 19. |
396 | | * (It's larger because the C++ compiler predates the "Visual" in |
397 | | * Visual C++.) |
398 | | * |
399 | | * So the product version number is 5 less than the compiler version |
400 | | * number. |
401 | | */ |
402 | | #define VCPP_MAJOR_VERSION (COMPILER_MAJOR_VERSION - 5) |
403 | | |
404 | | #if VCPP_MAJOR_VERSION == 14 |
405 | | /* |
406 | | * From https://devblogs.microsoft.com/cppblog/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2017/ |
407 | | * |
408 | | * We've been delivering improvements to Visual Studio 2017 more |
409 | | * frequently than ever before. Since its first release in March |
410 | | * we've released four major updates to VS2017 and are currently |
411 | | * previewing the fifth update, VS2017 version 15.5. |
412 | | * |
413 | | * The MSVC toolset in VS2017 is built as a minor version update to |
414 | | * the VS2015 compiler toolset. This minor version bump indicates |
415 | | * that the VS2017 MSVC toolset is binary compatible with the VS2015 |
416 | | * MSVC toolset, enabling an easier upgrade for VS2015 users. Even |
417 | | * though the MSVC compiler toolset in VS2017 delivers many new |
418 | | * features and conformance improvements it is a minor version, |
419 | | * compatible update from 14.00 in VS2015 to 14.10 in VS2017. |
420 | | */ |
421 | | #if COMPILER_MINOR_VERSION < 10 |
422 | | #define VS_VERSION "2015" |
423 | | #elif COMPILER_MINOR_VERSION < 20 |
424 | | #define VS_VERSION "2017" |
425 | | #elif COMPILER_MINOR_VERSION < 30 |
426 | | #define VS_VERSION "2019" |
427 | | #else |
428 | | #define VS_VERSION "2022" |
429 | | #endif |
430 | | #else |
431 | | /* |
432 | | * Add additional checks here, before the #else. |
433 | | */ |
434 | | #define VS_VERSION "(unknown)" |
435 | | #endif /* VCPP_MAJOR_VERSION */ |
436 | | |
437 | | /* |
438 | | * XXX - should we show the raw compiler version number, as is |
439 | | * shown by "cl /?", which would be %d.%d.%d.%d with |
440 | | * COMPILER_MAJOR_VERSION, COMPILER_MINOR_VERSION, |
441 | | * COMPILER_BUILD_NUMBER, and _MSC_BUILD, the last of which is |
442 | | * "the revision number element of the compiler's version number", |
443 | | * which I guess is not to be confused with the build number, |
444 | | * the _BUILD in the name nonwithstanding. |
445 | | */ |
446 | | g_string_append_printf(str, "Microsoft Visual Studio " VS_VERSION " (VC++ %d.%d, build %d)", |
447 | | VCPP_MAJOR_VERSION, COMPILER_MINOR_VERSION, COMPILER_BUILD_NUMBER); |
448 | | #if defined(__clang__) |
449 | | /* |
450 | | * See above. |
451 | | */ |
452 | | g_string_append_printf(str, " clang/C2 %s and -fno-ms-compatibility", |
453 | | __VERSION__); |
454 | | #endif |
455 | | #elif defined(__GNUC__) && defined(__VERSION__) |
456 | | /* |
457 | | * Clang and llvm-gcc also define __GNUC__ and __VERSION__; |
458 | | * distinguish between them. |
459 | | */ |
460 | 15 | #if defined(__clang__) |
461 | | /* clang */ |
462 | 15 | char *version; /* clang's version string has a trailing space. */ |
463 | 15 | #if defined(__clang_version__) |
464 | 15 | version = g_strdup(__clang_version__); |
465 | 15 | g_string_append_printf(str, "Clang %s", g_strstrip(version)); |
466 | | #else |
467 | | version = g_strdup(__VERSION__); |
468 | | g_string_append_printf(str, "%s", g_strstrip(version)); |
469 | | #endif /* __clang_version__ */ |
470 | 15 | g_free(version); |
471 | | #elif defined(__llvm__) |
472 | | /* llvm-gcc */ |
473 | | g_string_append_printf(str, "llvm-gcc %s", __VERSION__); |
474 | | #else |
475 | | /* boring old GCC */ |
476 | | g_string_append_printf(str, "GCC %s", __VERSION__); |
477 | | #endif |
478 | | #elif defined(__HP_aCC) |
479 | | g_string_append_printf(str, "HP aCC %d", __HP_aCC); |
480 | | #elif defined(__xlC__) |
481 | | g_string_append_printf(str, "IBM XL C %d.%d", |
482 | | (__xlC__ >> 8) & 0xFF, __xlC__ & 0xFF); |
483 | | #ifdef __IBMC__ |
484 | | if ((__IBMC__ % 10) != 0) |
485 | | g_string_append_printf(str, " patch %d", __IBMC__ % 10); |
486 | | #endif /* __IBMC__ */ |
487 | | #elif defined(__INTEL_COMPILER) |
488 | | g_string_append_printf(str, "Intel C %d.%d", |
489 | | __INTEL_COMPILER / 100, (__INTEL_COMPILER / 10) % 10); |
490 | | if ((__INTEL_COMPILER % 10) != 0) |
491 | | g_string_append_printf(str, " patch %d", __INTEL_COMPILER % 10); |
492 | | #ifdef __INTEL_COMPILER_BUILD_DATE |
493 | | g_string_sprinta(str, ", compiler built %04d-%02d-%02d", |
494 | | __INTEL_COMPILER_BUILD_DATE / 10000, |
495 | | (__INTEL_COMPILER_BUILD_DATE / 100) % 100, |
496 | | __INTEL_COMPILER_BUILD_DATE % 100); |
497 | | #endif /* __INTEL_COMPILER_BUILD_DATE */ |
498 | | #elif defined(__SUNPRO_C) |
499 | | g_string_append_printf(str, "Sun C %d.%d", |
500 | | (__SUNPRO_C >> 8) & 0xF, (__SUNPRO_C >> 4) & 0xF); |
501 | | if ((__SUNPRO_C & 0xF) != 0) |
502 | | g_string_append_printf(str, " patch %d", __SUNPRO_C & 0xF); |
503 | | #else |
504 | | g_string_append(str, "unknown compiler"); |
505 | | #endif |
506 | 15 | g_string_append(str, "\n"); |
507 | 15 | } |
508 | | |
509 | | void |
510 | | gather_pcre2_runtime_info(feature_list l) |
511 | 15 | { |
512 | | /* From pcre2_api(3): |
513 | | * The where argument should point to a buffer that is at least 24 code |
514 | | * units long. (The exact length required can be found by calling |
515 | | * pcre2_config() with where set to NULL.) |
516 | | * |
517 | | * The API should accept a buffer size as additional input. We could opt for a |
518 | | * stack buffer size greater than 24 but let's just go with the weirdness... |
519 | | */ |
520 | 15 | int size; |
521 | 15 | char *buf_pcre2; |
522 | | |
523 | 15 | size = pcre2_config(PCRE2_CONFIG_VERSION, NULL); |
524 | 15 | if (size < 0 || size > 255) { |
525 | 0 | without_feature(l, "PCRE2 (error querying)"); |
526 | 0 | return; |
527 | 0 | } |
528 | 15 | buf_pcre2 = g_malloc((size_t)size + 1); |
529 | 15 | pcre2_config(PCRE2_CONFIG_VERSION, buf_pcre2); |
530 | 15 | buf_pcre2[size] = '\0'; |
531 | 15 | with_feature(l, "PCRE2 %s", buf_pcre2); |
532 | 15 | g_free(buf_pcre2); |
533 | 15 | } |
534 | | |
535 | | void |
536 | | gather_xxhash_runtime_info(feature_list l) |
537 | 15 | { |
538 | 15 | (void)l; |
539 | | #if defined(HAVE_XXHASH) |
540 | | with_feature(l, "xxhash %u", XXH_versionNumber()); |
541 | | #endif |
542 | 15 | } |
543 | | |
544 | | void |
545 | | gather_zlib_runtime_info(feature_list l) |
546 | 15 | { |
547 | 15 | (void)l; |
548 | 15 | #if defined(HAVE_ZLIB) && !defined(_WIN32) |
549 | 15 | with_feature(l, "zlib %s", zlibVersion()); |
550 | 15 | #endif |
551 | 15 | } |
552 | | |
553 | | /* |
554 | | * Get various library run-time versions, and the OS version, and append |
555 | | * them to the specified GString. |
556 | | * |
557 | | * "additional_info" is called at the end to append any additional |
558 | | * information; this is required in order to, for example, put the |
559 | | * libcap information at the end of the string, as we currently |
560 | | * don't use libcap in TShark. |
561 | | */ |
562 | | GString * |
563 | | get_runtime_version_info(gather_feature_func gather_runtime) |
564 | 15 | { |
565 | 15 | GString *str; |
566 | 15 | char *lc; |
567 | 15 | GList *l = NULL, *with_list = NULL, *without_list = NULL; |
568 | | |
569 | 15 | str = g_string_new("Runtime info:\n OS: "); |
570 | 15 | get_os_version_info(str); |
571 | | |
572 | | /* CPU Info */ |
573 | 15 | g_string_append(str, "\n CPU: "); |
574 | 15 | get_cpu_info(str); |
575 | | |
576 | | /* Get info about installed memory */ |
577 | 15 | g_string_append(str, "\n Memory: "); |
578 | 15 | get_mem_info(str); |
579 | | |
580 | 15 | g_string_append_printf(str, "\n GLib: %u.%u.%u\n", |
581 | 15 | glib_major_version, glib_minor_version, glib_micro_version); |
582 | | /* |
583 | | * Display LC_CTYPE as a relevant, portable and sort of representative |
584 | | * locale configuration without being exceedingly verbose and including |
585 | | * the whole shebang of categories using LC_ALL. |
586 | | */ |
587 | 15 | if ((lc = setlocale(LC_CTYPE, NULL)) != NULL) { |
588 | 15 | g_string_append_printf(str, " Locale: LC_TYPE=%s\n", lc); |
589 | 15 | } |
590 | | #ifdef HAVE_PLUGINS |
591 | | if (g_module_supported()) { |
592 | | g_string_append_printf(str, " Plugins: supported, %d loaded\n", plugins_get_count()); |
593 | | } |
594 | | else { |
595 | | g_string_append(str, " Plugins: not supported by platform\n"); |
596 | | } |
597 | | #else |
598 | 15 | g_string_append(str, " Plugins: disabled at compile time\n"); |
599 | 15 | #endif |
600 | | |
601 | 15 | if (gather_runtime != NULL) { |
602 | 15 | gather_runtime(&l); |
603 | 15 | } |
604 | | |
605 | 15 | sort_features(&l); |
606 | 15 | separate_features(&l, &with_list, &without_list); |
607 | 15 | free_features(&l); |
608 | | |
609 | 15 | if (with_list != NULL) { |
610 | 15 | g_string_append(str, " With:\n"); |
611 | 15 | features_to_columns(&with_list, str); |
612 | 15 | free_features(&with_list); |
613 | 15 | } |
614 | 15 | if (without_list != NULL) { |
615 | 0 | g_string_append(str, " Without:\n"); |
616 | 0 | features_to_columns(&without_list, str); |
617 | 0 | free_features(&without_list); |
618 | 0 | } |
619 | | |
620 | 15 | end_string(str); |
621 | 15 | return str; |
622 | 15 | } |
623 | | |
624 | | void |
625 | | get_ws_version_number(int *major, int *minor, int *micro) |
626 | 0 | { |
627 | 0 | if (major) |
628 | 0 | *major = VERSION_MAJOR; |
629 | 0 | if (minor) |
630 | 0 | *minor = VERSION_MINOR; |
631 | 0 | if (micro) |
632 | 0 | *micro = VERSION_MICRO; |
633 | 0 | } |
634 | | |
635 | | void |
636 | | show_version(void) |
637 | 0 | { |
638 | 0 | printf("%s.\n\n" |
639 | 0 | "%s" |
640 | 0 | "%s\n" |
641 | 0 | "%s\n" |
642 | 0 | "%s", |
643 | 0 | appname_with_version, |
644 | 0 | copyright_info, |
645 | 0 | license_info, |
646 | 0 | comp_info, |
647 | 0 | runtime_info); |
648 | 0 | } |
649 | | |
650 | | void |
651 | | show_help_header(const char *description) |
652 | 0 | { |
653 | 0 | printf("%s\n", appname_with_version); |
654 | 0 | if (description) { |
655 | 0 | printf("%s\n", description); |
656 | 0 | printf("See https://www.wireshark.org for more information.\n"); |
657 | 0 | } |
658 | 0 | } |
659 | | |
660 | | /* |
661 | | * Get copyright information. |
662 | | */ |
663 | | const char * |
664 | | get_copyright_info(void) |
665 | 15 | { |
666 | 15 | return |
667 | 15 | "Copyright 1998-2026 Gerald Combs <gerald@wireshark.org> and contributors."; |
668 | 15 | } |
669 | | |
670 | | const char * |
671 | | get_license_info_short(void) |
672 | 15 | { |
673 | 15 | return |
674 | 15 | "Licensed under the terms of the GNU General Public License (version 2 or later). " |
675 | 15 | "This is free software; see the file named COPYING in the distribution. " |
676 | 15 | "There is NO WARRANTY; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."; |
677 | 15 | } |
678 | | |
679 | | const char * |
680 | | get_license_info(void) |
681 | 0 | { |
682 | 0 | return |
683 | 0 | "This program is free software: you can redistribute it and/or modify " |
684 | 0 | "it under the terms of the GNU General Public License as published by " |
685 | 0 | "the Free Software Foundation, either version 2 of the License, or " |
686 | 0 | "(at your option) any later version. This program is distributed in the " |
687 | 0 | "hope that it will be useful, but WITHOUT ANY WARRANTY; without even " |
688 | 0 | "the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. " |
689 | 0 | "See the GNU General Public License for more details."; |
690 | 0 | } |
691 | | |
692 | | /* |
693 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
694 | | * |
695 | | * Local variables: |
696 | | * c-basic-offset: 8 |
697 | | * tab-width: 8 |
698 | | * indent-tabs-mode: t |
699 | | * End: |
700 | | * |
701 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
702 | | * :indentSize=8:tabSize=8:noTabs=false: |
703 | | */ |