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