plaintext=decrypt_krb5_data => enc_key_t
[metze/wireshark/wip.git] / version_info.c
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
13 #include <stdio.h>
14 #include <stdlib.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
29 #ifdef HAVE_ZLIB
30 #include <zlib.h>
31 #endif
32
33 #include "version.h"
34
35 #include "version_info.h"
36
37 #include <wsutil/cpu_info.h>
38 #include <wsutil/copyright_info.h>
39 #include <wsutil/os_version_info.h>
40 #include <wsutil/crash_info.h>
41 #include <wsutil/ws_printf.h> /* ws_debug_printf */
42 #include <wsutil/plugins.h>
43
44 static char *appname_with_version;
45 static char *comp_info;
46 static char *runtime_info;
47
48 void
49 ws_init_version_info(const char *appname,
50     void (*prepend_compile_time_info)(GString *),
51     void (*append_compile_time_info)(GString *),
52     void (*additional_run_time_info)(GString *))
53 {
54         GString *comp_info_str, *runtime_info_str;
55
56         /*
57          * Combine the supplied application name string with the
58          * version - including the VCS version, for a build from
59          * a checkout.
60          */
61         appname_with_version = g_strdup_printf("%s %s",
62             appname, get_ws_vcs_version_info());
63
64         /* Get the compile-time version information string */
65         comp_info_str = get_compiled_version_info(prepend_compile_time_info,
66             append_compile_time_info);
67
68         /* Get the run-time version information string */
69         runtime_info_str = get_runtime_version_info(additional_run_time_info);
70
71         comp_info = g_string_free(comp_info_str, FALSE);
72         runtime_info = g_string_free(runtime_info_str, FALSE);
73
74         /* Add this information to the information to be reported on a crash. */
75         ws_add_crash_info("%s\n"
76             "\n"
77             "%s\n"
78             "%s",
79             appname_with_version, comp_info, runtime_info);
80 }
81
82 const char *
83 get_appname_and_version(void)
84 {
85         return appname_with_version;
86 }
87
88 /*
89  * If the string doesn't end with a newline, append one.
90  * Then word-wrap it to 80 columns.
91  */
92 static void
93 end_string(GString *str)
94 {
95         size_t point;
96         char *p, *q;
97
98         point = str->len;
99         if (point == 0 || str->str[point - 1] != '\n')
100                 g_string_append(str, "\n");
101         p = str->str;
102         while (*p != '\0') {
103                 q = strchr(p, '\n');
104                 if (q - p > 80) {
105                         /*
106                          * Break at or before this point.
107                          */
108                         q = p + 80;
109                         while (q > p && *q != ' ')
110                                 q--;
111                         if (q != p)
112                                 *q = '\n';
113                 }
114                 p = q + 1;
115         }
116 }
117
118 static const gchar *
119 get_zlib_compiled_version_info(void)
120 {
121 #ifdef HAVE_ZLIB
122 #ifdef ZLIB_VERSION
123         return "with zlib "ZLIB_VERSION;
124 #else
125         return "with zlib (version unknown)";
126 #endif /* ZLIB_VERSION */
127 #else
128         return "without zlib";
129 #endif /* HAVE_ZLIB */
130 }
131
132 /*
133  * Get various library compile-time versions, put them in a GString,
134  * and return the GString.
135  *
136  * "prepend_info" is called at the start to prepend any additional
137  * information before the standard library information.
138  *
139  * "append_info" is called at the end to append any additional
140  * information after the standard library information.  This is
141  * required in order to, for example, put Qt information at the
142  * end of the string, as we don't use Qt in TShark.
143  */
144 GString *
145 get_compiled_version_info(void (*prepend_info)(GString *),
146                           void (*append_info)(GString *))
147 {
148         GString *str;
149
150         str = g_string_new("Compiled ");
151
152         if (sizeof(str) == 4)
153                 g_string_append(str, "(32-bit) ");
154         else
155                 g_string_append(str, "(64-bit) ");
156
157         if (prepend_info) {
158                 (*prepend_info)(str);
159                 g_string_append(str, ", ");
160         }
161
162         /* GLIB */
163         g_string_append(str, "with ");
164         g_string_append_printf(str,
165 #ifdef GLIB_MAJOR_VERSION
166             "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
167             GLIB_MICRO_VERSION);
168 #else
169             "GLib (version unknown)");
170 #endif
171
172         g_string_append_printf(str, ", %s", get_zlib_compiled_version_info());
173
174         /* Additional application-dependent information */
175         if (append_info)
176                 (*append_info)(str);
177         g_string_append(str, ".");
178
179         end_string(str);
180
181         return str;
182 }
183
184 static void
185 get_mem_info(GString *str)
186 {
187         gint64 memsize = 0;
188
189 #ifdef _WIN32
190         MEMORYSTATUSEX statex;
191
192         statex.dwLength = sizeof (statex);
193
194         if (GlobalMemoryStatusEx(&statex))
195                 memsize = statex.ullTotalPhys;
196 #elif __APPLE__
197         size_t len = sizeof(memsize);
198         sysctlbyname("hw.memsize", &memsize, &len, NULL, 0);
199 #elif __linux__
200         struct sysinfo info;
201         if (sysinfo(&info) == 0)
202                 memsize = info.totalram * info.mem_unit;
203 #endif
204
205         if (memsize > 0)
206                 g_string_append_printf(str, ", with ""%" G_GINT64_MODIFIER "d" " MB of physical memory", memsize/(1024*1024));
207 }
208
209 /*
210  * Get compiler information, and append it to the GString.
211  */
212 static void
213 get_compiler_info(GString *str)
214 {
215         /*
216          * See https://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers
217          * information on various defined strings.
218          *
219          * GCC's __VERSION__ is a nice text string for humans to
220          * read.  The page at sourceforge.net largely describes
221          * numeric #defines that encode the version; if the compiler
222          * doesn't also offer a nice printable string, we try prettifying
223          * the number somehow.
224          */
225 #if defined(_MSC_FULL_VER)
226         /*
227          * We check for this first, as Microsoft have a version of their
228          * compiler that has Clang as the front end and their code generator
229          * as the back end.
230          *
231          * My head asplode.
232          */
233
234         /* As of Wireshark 3.0, we support only Visual Studio 2015 (14.x)
235          * or later.
236          *
237          * https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd
238          * has a *large* table of Microsoft product names, VC++ versions,
239          * _MSC_VER values, and _MSC_FULL_VER values.  All the versions
240          * we support define _MSC_FULL_VER.  We don't bother trying to
241          * get the SP/update/version number from the build number, as
242          * we'd have to keep updating that with every update; there's no
243          * way to get that information directly from a predefine, and in
244          * some cases multiple updates/versions have the *same* build
245          * number (because they didn't update the toolchain).
246          *
247          * https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2017
248          * defines the format of _MSC_VER and _MSC_FULL_VER.  _MSC_FULL_VER
249          * is a decimal number of the form MMmmBBBBB, where MM is the compiler/
250          * toolchain major version, mm is the minor version, and BBBBB is the
251          * build.  We break it down based on that.
252          */
253   #define COMPILER_MAJOR_VERSION         (_MSC_FULL_VER / 10000000)
254   #define COMPILER_MINOR_VERSION        ((_MSC_FULL_VER % 10000000) / 100000)
255   #define COMPILER_BUILD_NUMBER          (_MSC_FULL_VER % 100000)
256
257         /*
258          * From https://blogs.msdn.microsoft.com/vcblog/2014/11/17/c111417-features-in-vs-2015-preview/
259          *
260          *  Bakersfield: DevDiv's upper management determines the scheduling
261          *  of new major versions.  They also decided to increment the product
262          *  version from 12 (for VS 2013) to 14 (for VS 2015).  However, the
263          *  C++ compiler's version incremented normally, from 18 to 19.
264          *  (It's larger because the C++ compiler predates the "Visual" in
265          *  Visual C++.)
266          *
267          * So the product version number is 5 less than the compiler version
268          * number.
269          */
270   #define VCPP_MAJOR_VERSION    (COMPILER_MAJOR_VERSION - 5)
271
272   #if VCPP_MAJOR_VERSION == 14
273         /*
274          * From https://blogs.msdn.microsoft.com/vcblog/2017/11/15/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2017/:
275          *
276          *  We've been delivering improvements to Visual Studio 2017 more
277          *  frequently than ever before. Since its first release in March
278          *  we've released four major updates to VS2017 and are currently
279          *  previewing the fifth update, VS2017 version 15.5.
280          *
281          *  The MSVC toolset in VS2017 is built as a minor version update to
282          *  the VS2015 compiler toolset. This minor version bump indicates
283          *  that the VS2017 MSVC toolset is binary compatible with the VS2015
284          *  MSVC toolset, enabling an easier upgrade for VS2015 users. Even
285          *  though the MSVC compiler toolset in VS2017 delivers many new
286          *  features and conformance improvements it is a minor version,
287          *  compatible update from 14.00 in VS2015 to 14.10 in VS2017.
288          */
289     #if COMPILER_MINOR_VERSION < 10
290       #define VS_VERSION        "2015"
291     #else
292       #define VS_VERSION        "2017"
293     #endif
294   #else
295     /*
296      * Add additional checks here, before the #else.
297      */
298     #define VS_VERSION  "(unknown)"
299   #endif /* VCPP_MAJOR_VERSION */
300
301         /*
302          * XXX - should we show the raw compiler version number, as is
303          * shown by "cl /?", which would be %d.%d.%d.%d with
304          * COMPILER_MAJOR_VERSION, COMPILER_MINOR_VERSION,
305          * COMPILER_BUILD_NUMBER, and _MSC_BUILD, the last of which is
306          * "the revision number element of the compiler's version number",
307          * which I guess is not to be confused with the build number,
308          * the _BUILD in the name nonwithstanding.
309          */
310         g_string_append_printf(str, "\n\nBuilt using Microsoft Visual Studio " VS_VERSION " (VC++ %d.%d, build %d)",
311             VCPP_MAJOR_VERSION, COMPILER_MINOR_VERSION, COMPILER_BUILD_NUMBER);
312   #if defined(__clang__)
313         /*
314          * See above.
315          */
316         g_string_append_printf(str, " clang/C2 %s and -fno-ms-compatibility.\n",
317             __VERSION__);
318   #else
319         g_string_append_printf(str, ".\n");
320   #endif
321 #elif defined(__GNUC__) && defined(__VERSION__)
322         /*
323          * Clang and llvm-gcc also define __GNUC__ and __VERSION__;
324          * distinguish between them.
325          */
326   #if defined(__clang__)
327         /*
328          * We know this isn't clang/C2, as _MSC_FULL_VER isn't defined.
329          */
330         g_string_append_printf(str, "\n\nBuilt using clang %s.\n", __VERSION__);
331   #elif defined(__llvm__)
332         /* llvm-gcc */
333         g_string_append_printf(str, "\n\nBuilt using llvm-gcc %s.\n", __VERSION__);
334   #else /* boring old GCC */
335         g_string_append_printf(str, "\n\nBuilt using gcc %s.\n", __VERSION__);
336   #endif /* llvm */
337 #elif defined(__HP_aCC)
338         g_string_append_printf(str, "\n\nBuilt using HP aCC %d.\n", __HP_aCC);
339 #elif defined(__xlC__)
340         g_string_append_printf(str, "\n\nBuilt using IBM XL C %d.%d\n",
341             (__xlC__ >> 8) & 0xFF, __xlC__ & 0xFF);
342   #ifdef __IBMC__
343         if ((__IBMC__ % 10) != 0)
344                 g_string_append_printf(str, " patch %d", __IBMC__ % 10);
345   #endif /* __IBMC__ */
346         g_string_append_printf(str, "\n");
347 #elif defined(__INTEL_COMPILER)
348         g_string_append_printf(str, "\n\nBuilt using Intel C %d.%d",
349             __INTEL_COMPILER / 100, (__INTEL_COMPILER / 10) % 10);
350         if ((__INTEL_COMPILER % 10) != 0)
351                 g_string_append_printf(str, " patch %d", __INTEL_COMPILER % 10);
352   #ifdef __INTEL_COMPILER_BUILD_DATE
353         g_string_sprinta(str, ", compiler built %04d-%02d-%02d",
354             __INTEL_COMPILER_BUILD_DATE / 10000,
355             (__INTEL_COMPILER_BUILD_DATE / 100) % 100,
356             __INTEL_COMPILER_BUILD_DATE % 100);
357   #endif /* __INTEL_COMPILER_BUILD_DATE */
358         g_string_append_printf(str, "\n");
359 #elif defined(__SUNPRO_C)
360         g_string_append_printf(str, "\n\nBuilt using Sun C %d.%d",
361             (__SUNPRO_C >> 8) & 0xF, (__SUNPRO_C >> 4) & 0xF);
362         if ((__SUNPRO_C & 0xF) != 0)
363                 g_string_append_printf(str, " patch %d", __SUNPRO_C & 0xF);
364         g_string_append_printf(str, "\n");
365 #endif
366 }
367
368 /* XXX - is the setlocale() return string opaque? For glibc the separator is ';' */
369 static gchar *
370 get_locale(void)
371 {
372         const gchar *lang;
373         gchar **locv, *loc;
374
375         lang = setlocale(LC_ALL, NULL);
376         if (lang == NULL) {
377                 return NULL;
378         }
379
380         locv = g_strsplit(lang, ";", -1);
381         loc = g_strjoinv(", ", locv);
382         g_strfreev(locv);
383         return loc;
384 }
385
386 /*
387  * Get various library run-time versions, and the OS version, and append
388  * them to the specified GString.
389  *
390  * "additional_info" is called at the end to append any additional
391  * information; this is required in order to, for example, put the
392  * libcap information at the end of the string, as we currently
393  * don't use libcap in TShark.
394  */
395 GString *
396 get_runtime_version_info(void (*additional_info)(GString *))
397 {
398         GString *str;
399         gchar *lang;
400
401         str = g_string_new("Running on ");
402
403         get_os_version_info(str);
404
405         /* CPU Info */
406         get_cpu_info(str);
407
408         /* Get info about installed memory */
409         get_mem_info(str);
410
411         /*
412          * Locale.
413          *
414          * This returns the C language's locale information; this
415          * returns the locale that's actually in effect, even if
416          * it doesn't happen to match the settings of any of the
417          * locale environment variables.
418          *
419          * On Windows get_locale returns the full language, country
420          * name, and code page, e.g. "English_United States.1252":
421          * https://msdn.microsoft.com/en-us/library/x99tb11d.aspx
422          */
423         if ((lang = get_locale()) != NULL) {
424                 g_string_append_printf(str, ", with locale %s", lang);
425                 g_free(lang);
426         }
427         else {
428                 g_string_append(str, ", with default locale");
429         }
430
431
432         /* Additional application-dependent information */
433         if (additional_info)
434                 (*additional_info)(str);
435
436         /* zlib */
437 #if defined(HAVE_ZLIB) && !defined(_WIN32)
438         g_string_append_printf(str, ", with zlib %s", zlibVersion());
439 #endif
440
441         /* plugins */
442 #ifdef HAVE_PLUGINS
443         if (g_module_supported()) {
444                 g_string_append_printf(str, ", binary plugins supported (%d loaded)", plugins_get_count());
445         }
446         else {
447                 g_string_append(str, ", binary plugins not supported");
448         }
449 #endif
450
451         g_string_append(str, ".");
452
453         /* Compiler info */
454         get_compiler_info(str);
455
456         end_string(str);
457
458         return str;
459 }
460
461 /*
462  * Return a version number string for Wireshark, including, for builds
463  * from a tree checked out from Wireshark's version control system,
464  * something identifying what version was checked out.
465  */
466 const char *
467 get_ws_vcs_version_info(void)
468 {
469 #ifdef VCSVERSION
470         return VERSION " (" VCSVERSION ")";
471 #else
472         return VERSION;
473 #endif
474 }
475
476 void
477 get_ws_version_number(int *major, int *minor, int *micro)
478 {
479         if (major)
480                 *major = VERSION_MAJOR;
481         if (minor)
482                 *minor = VERSION_MINOR;
483         if (micro)
484                 *micro = VERSION_MICRO;
485 }
486
487 void
488 show_version(void)
489 {
490         ws_debug_printf("%s\n"
491                "\n"
492                "%s\n"
493                "%s\n"
494                "%s",
495                appname_with_version, get_copyright_info(),
496                comp_info, runtime_info);
497 }
498
499 void
500 show_help_header(const char *description)
501 {
502         ws_debug_printf("%s\n"
503                 "%s\n"
504                 "See https://www.wireshark.org for more information.\n",
505                 appname_with_version, description);
506 }
507
508 /*
509  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
510  *
511  * Local variables:
512  * c-basic-offset: 8
513  * tab-width: 8
514  * indent-tabs-mode: t
515  * End:
516  *
517  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
518  * :indentSize=8:tabSize=8:noTabs=false:
519  */