HTTPS (almost) everywhere.
[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     #elif COMPILER_MINOR_VERSION < 20
292       #define VS_VERSION        "2017"
293     #else
294       #define VS_VERSION        "2019"
295     #endif
296   #else
297     /*
298      * Add additional checks here, before the #else.
299      */
300     #define VS_VERSION  "(unknown)"
301   #endif /* VCPP_MAJOR_VERSION */
302
303         /*
304          * XXX - should we show the raw compiler version number, as is
305          * shown by "cl /?", which would be %d.%d.%d.%d with
306          * COMPILER_MAJOR_VERSION, COMPILER_MINOR_VERSION,
307          * COMPILER_BUILD_NUMBER, and _MSC_BUILD, the last of which is
308          * "the revision number element of the compiler's version number",
309          * which I guess is not to be confused with the build number,
310          * the _BUILD in the name nonwithstanding.
311          */
312         g_string_append_printf(str, "\n\nBuilt using Microsoft Visual Studio " VS_VERSION " (VC++ %d.%d, build %d)",
313             VCPP_MAJOR_VERSION, COMPILER_MINOR_VERSION, COMPILER_BUILD_NUMBER);
314   #if defined(__clang__)
315         /*
316          * See above.
317          */
318         g_string_append_printf(str, " clang/C2 %s and -fno-ms-compatibility.\n",
319             __VERSION__);
320   #else
321         g_string_append_printf(str, ".\n");
322   #endif
323 #elif defined(__GNUC__) && defined(__VERSION__)
324         /*
325          * Clang and llvm-gcc also define __GNUC__ and __VERSION__;
326          * distinguish between them.
327          */
328   #if defined(__clang__)
329         /*
330          * We know this isn't clang/C2, as _MSC_FULL_VER isn't defined.
331          */
332         g_string_append_printf(str, "\n\nBuilt using clang %s.\n", __VERSION__);
333   #elif defined(__llvm__)
334         /* llvm-gcc */
335         g_string_append_printf(str, "\n\nBuilt using llvm-gcc %s.\n", __VERSION__);
336   #else /* boring old GCC */
337         g_string_append_printf(str, "\n\nBuilt using gcc %s.\n", __VERSION__);
338   #endif /* llvm */
339 #elif defined(__HP_aCC)
340         g_string_append_printf(str, "\n\nBuilt using HP aCC %d.\n", __HP_aCC);
341 #elif defined(__xlC__)
342         g_string_append_printf(str, "\n\nBuilt using IBM XL C %d.%d\n",
343             (__xlC__ >> 8) & 0xFF, __xlC__ & 0xFF);
344   #ifdef __IBMC__
345         if ((__IBMC__ % 10) != 0)
346                 g_string_append_printf(str, " patch %d", __IBMC__ % 10);
347   #endif /* __IBMC__ */
348         g_string_append_printf(str, "\n");
349 #elif defined(__INTEL_COMPILER)
350         g_string_append_printf(str, "\n\nBuilt using Intel C %d.%d",
351             __INTEL_COMPILER / 100, (__INTEL_COMPILER / 10) % 10);
352         if ((__INTEL_COMPILER % 10) != 0)
353                 g_string_append_printf(str, " patch %d", __INTEL_COMPILER % 10);
354   #ifdef __INTEL_COMPILER_BUILD_DATE
355         g_string_sprinta(str, ", compiler built %04d-%02d-%02d",
356             __INTEL_COMPILER_BUILD_DATE / 10000,
357             (__INTEL_COMPILER_BUILD_DATE / 100) % 100,
358             __INTEL_COMPILER_BUILD_DATE % 100);
359   #endif /* __INTEL_COMPILER_BUILD_DATE */
360         g_string_append_printf(str, "\n");
361 #elif defined(__SUNPRO_C)
362         g_string_append_printf(str, "\n\nBuilt using Sun C %d.%d",
363             (__SUNPRO_C >> 8) & 0xF, (__SUNPRO_C >> 4) & 0xF);
364         if ((__SUNPRO_C & 0xF) != 0)
365                 g_string_append_printf(str, " patch %d", __SUNPRO_C & 0xF);
366         g_string_append_printf(str, "\n");
367 #endif
368 }
369
370 /* XXX - is the setlocale() return string opaque? For glibc the separator is ';' */
371 static gchar *
372 get_locale(void)
373 {
374         const gchar *lang;
375         gchar **locv, *loc;
376
377         lang = setlocale(LC_ALL, NULL);
378         if (lang == NULL) {
379                 return NULL;
380         }
381
382         locv = g_strsplit(lang, ";", -1);
383         loc = g_strjoinv(", ", locv);
384         g_strfreev(locv);
385         return loc;
386 }
387
388 /*
389  * Get various library run-time versions, and the OS version, and append
390  * them to the specified GString.
391  *
392  * "additional_info" is called at the end to append any additional
393  * information; this is required in order to, for example, put the
394  * libcap information at the end of the string, as we currently
395  * don't use libcap in TShark.
396  */
397 GString *
398 get_runtime_version_info(void (*additional_info)(GString *))
399 {
400         GString *str;
401         gchar *lang;
402
403         str = g_string_new("Running on ");
404
405         get_os_version_info(str);
406
407         /* CPU Info */
408         get_cpu_info(str);
409
410         /* Get info about installed memory */
411         get_mem_info(str);
412
413         /*
414          * Locale.
415          *
416          * This returns the C language's locale information; this
417          * returns the locale that's actually in effect, even if
418          * it doesn't happen to match the settings of any of the
419          * locale environment variables.
420          *
421          * On Windows get_locale returns the full language, country
422          * name, and code page, e.g. "English_United States.1252":
423          * https://msdn.microsoft.com/en-us/library/x99tb11d.aspx
424          */
425         if ((lang = get_locale()) != NULL) {
426                 g_string_append_printf(str, ", with locale %s", lang);
427                 g_free(lang);
428         }
429         else {
430                 g_string_append(str, ", with default locale");
431         }
432
433
434         /* Additional application-dependent information */
435         if (additional_info)
436                 (*additional_info)(str);
437
438         /* zlib */
439 #if defined(HAVE_ZLIB) && !defined(_WIN32)
440         g_string_append_printf(str, ", with zlib %s", zlibVersion());
441 #endif
442
443         /* plugins */
444 #ifdef HAVE_PLUGINS
445         if (g_module_supported()) {
446                 g_string_append_printf(str, ", binary plugins supported (%d loaded)", plugins_get_count());
447         }
448         else {
449                 g_string_append(str, ", binary plugins not supported");
450         }
451 #endif
452
453         g_string_append(str, ".");
454
455         /* Compiler info */
456         get_compiler_info(str);
457
458         end_string(str);
459
460         return str;
461 }
462
463 /*
464  * Return a version number string for Wireshark, including, for builds
465  * from a tree checked out from Wireshark's version control system,
466  * something identifying what version was checked out.
467  */
468 const char *
469 get_ws_vcs_version_info(void)
470 {
471 #ifdef VCSVERSION
472         return VERSION " (" VCSVERSION ")";
473 #else
474         return VERSION;
475 #endif
476 }
477
478 void
479 get_ws_version_number(int *major, int *minor, int *micro)
480 {
481         if (major)
482                 *major = VERSION_MAJOR;
483         if (minor)
484                 *minor = VERSION_MINOR;
485         if (micro)
486                 *micro = VERSION_MICRO;
487 }
488
489 void
490 show_version(void)
491 {
492         ws_debug_printf("%s\n"
493                "\n"
494                "%s\n"
495                "%s\n"
496                "%s",
497                appname_with_version, get_copyright_info(),
498                comp_info, runtime_info);
499 }
500
501 void
502 show_help_header(const char *description)
503 {
504         ws_debug_printf("%s\n"
505                 "%s\n"
506                 "See https://www.wireshark.org for more information.\n",
507                 appname_with_version, description);
508 }
509
510 /*
511  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
512  *
513  * Local variables:
514  * c-basic-offset: 8
515  * tab-width: 8
516  * indent-tabs-mode: t
517  * End:
518  *
519  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
520  * :indentSize=8:tabSize=8:noTabs=false:
521  */