[Automatic update for 2016-12-25]
[metze/wireshark/wip.git] / ws_version_info.c
1 /* ws_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  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include <config.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <locale.h>
29
30 #ifdef _WIN32
31 #include <windows.h>
32 #elif __APPLE__
33 #include <sys/types.h>
34 #include <sys/sysctl.h>
35 #elif __linux__
36 #include <sys/sysinfo.h>
37 #endif
38
39 #include <glib.h>
40
41 #ifdef HAVE_ZLIB
42 #include <zlib.h>
43 #endif
44
45 #include "version.h"
46
47 #include "ws_version_info.h"
48
49 #include <wsutil/cpu_info.h>
50 #include <wsutil/copyright_info.h>
51 #include <wsutil/os_version_info.h>
52 #include <wsutil/ws_printf.h> /* ws_debug_printf */
53
54 /*
55  * If the string doesn't end with a newline, append one.
56  * Then word-wrap it to 80 columns.
57  */
58 static void
59 end_string(GString *str)
60 {
61         size_t point;
62         char *p, *q;
63
64         point = str->len;
65         if (point == 0 || str->str[point - 1] != '\n')
66                 g_string_append(str, "\n");
67         p = str->str;
68         while (*p != '\0') {
69                 q = strchr(p, '\n');
70                 if (q - p > 80) {
71                         /*
72                          * Break at or before this point.
73                          */
74                         q = p + 80;
75                         while (q > p && *q != ' ')
76                                 q--;
77                         if (q != p)
78                                 *q = '\n';
79                 }
80                 p = q + 1;
81         }
82 }
83
84 static const gchar *
85 get_zlib_compiled_version_info(void)
86 {
87 #ifdef HAVE_ZLIB
88 #ifdef ZLIB_VERSION
89         return "with zlib "ZLIB_VERSION;
90 #else
91         return "with zlib (version unknown)";
92 #endif /* ZLIB_VERSION */
93 #else
94         return "without zlib";
95 #endif /* HAVE_ZLIB */
96 }
97
98 /*
99  * Get various library compile-time versions, put them in a GString,
100  * and return the GString.
101  *
102  * "prepend_info" is called at the start to prepend any additional
103  * information before the standard library information.
104  *
105  * "append_info" is called at the end to append any additional
106  * information after the standard library information.  This is
107  * required in order to, for example, put the Portaudio information
108  * at the end of the string, as we currently don't use Portaudio in
109  * TShark.
110  */
111 GString *
112 get_compiled_version_info(void (*prepend_info)(GString *),
113                           void (*append_info)(GString *))
114 {
115         GString *str;
116
117         str = g_string_new("Compiled ");
118
119         if (sizeof(str) == 4)
120                 g_string_append(str, "(32-bit) ");
121         else
122                 g_string_append(str, "(64-bit) ");
123
124         if (prepend_info) {
125                 (*prepend_info)(str);
126                 g_string_append(str, ", ");
127         }
128
129         /* GLIB */
130         g_string_append(str, "with ");
131         g_string_append_printf(str,
132 #ifdef GLIB_MAJOR_VERSION
133             "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
134             GLIB_MICRO_VERSION);
135 #else
136             "GLib (version unknown)");
137 #endif
138
139         g_string_append_printf(str, ", %s", get_zlib_compiled_version_info());
140
141         /* Additional application-dependent information */
142         if (append_info)
143                 (*append_info)(str);
144         g_string_append(str, ".");
145
146         end_string(str);
147
148         return str;
149 }
150
151 static void
152 get_mem_info(GString *str)
153 {
154         gint64 memsize = 0;
155
156 #ifdef _WIN32
157         MEMORYSTATUSEX statex;
158
159         statex.dwLength = sizeof (statex);
160
161         if (GlobalMemoryStatusEx(&statex))
162                 memsize = statex.ullTotalPhys;
163 #elif __APPLE__
164         size_t len = sizeof(memsize);
165         sysctlbyname("hw.memsize", &memsize, &len, NULL, 0);
166 #elif __linux__
167         struct sysinfo info;
168         if (sysinfo(&info) == 0)
169                 memsize = info.totalram * info.mem_unit;
170 #endif
171
172         if (memsize > 0)
173                 g_string_append_printf(str, ", with ""%" G_GINT64_MODIFIER "d" " MB of physical memory", memsize/(1024*1024));
174 }
175
176 /*
177  * Get compiler information, and append it to the GString.
178  */
179 static void
180 get_compiler_info(GString *str)
181 {
182         /*
183          * See https://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers
184          * information on various defined strings.
185          *
186          * GCC's __VERSION__ is a nice text string for humans to
187          * read.  The page at sourceforge.net largely describes
188          * numeric #defines that encode the version; if the compiler
189          * doesn't also offer a nice printable string, we try prettifying
190          * the number somehow.
191          */
192 #if defined(__GNUC__) && defined(__VERSION__)
193         /*
194          * Clang and llvm-gcc also define __GNUC__ and __VERSION__;
195          * distinguish between them.
196          */
197 #if defined(__clang__)
198         g_string_append_printf(str, "\n\nBuilt using clang %s.\n", __VERSION__);
199 #elif defined(__llvm__)
200         g_string_append_printf(str, "\n\nBuilt using llvm-gcc %s.\n", __VERSION__);
201 #else /* boring old GCC */
202         g_string_append_printf(str, "\n\nBuilt using gcc %s.\n", __VERSION__);
203 #endif /* llvm */
204 #elif defined(__HP_aCC)
205         g_string_append_printf(str, "\n\nBuilt using HP aCC %d.\n", __HP_aCC);
206 #elif defined(__xlC__)
207         g_string_append_printf(str, "\n\nBuilt using IBM XL C %d.%d\n",
208             (__xlC__ >> 8) & 0xFF, __xlC__ & 0xFF);
209 #ifdef __IBMC__
210         if ((__IBMC__ % 10) != 0)
211                 g_string_append_printf(str, " patch %d", __IBMC__ % 10);
212 #endif /* __IBMC__ */
213         g_string_append_printf(str, "\n");
214 #elif defined(__INTEL_COMPILER)
215         g_string_append_printf(str, "\n\nBuilt using Intel C %d.%d",
216             __INTEL_COMPILER / 100, (__INTEL_COMPILER / 10) % 10);
217         if ((__INTEL_COMPILER % 10) != 0)
218                 g_string_append_printf(str, " patch %d", __INTEL_COMPILER % 10);
219 #ifdef __INTEL_COMPILER_BUILD_DATE
220         g_string_sprinta(str, ", compiler built %04d-%02d-%02d",
221             __INTEL_COMPILER_BUILD_DATE / 10000,
222             (__INTEL_COMPILER_BUILD_DATE / 100) % 100,
223             __INTEL_COMPILER_BUILD_DATE % 100);
224 #endif /* __INTEL_COMPILER_BUILD_DATE */
225         g_string_append_printf(str, "\n");
226 #elif defined(_MSC_FULL_VER)
227 # if _MSC_FULL_VER > 99999999
228         /* Quote from the web:
229          * Bakersfield: DevDiv's upper management determines the scheduling of new major versions.
230          * They also decided to increment the product version from 12 (for VS 2013) to 14 (for VS 2015).
231          * However, the C++ compiler's version incremented normally, from 18 to 19.
232          * (It's larger because the C++ compiler predates the "Visual" in Visual C++.)
233          * XXX? Should we just output the compiler version?
234          */
235     int compiler_major_version = (_MSC_FULL_VER / 10000000), visual_studio_ver;
236
237     if (compiler_major_version < 19) {
238         visual_studio_ver = compiler_major_version - 6;
239     }else{
240         visual_studio_ver = compiler_major_version - 5;
241     }
242
243     g_string_append_printf(str, "\n\nBuilt using Microsoft Visual C++ %d.%d",
244                    visual_studio_ver,
245                                (_MSC_FULL_VER / 100000) % 100);
246 #  if (_MSC_FULL_VER % 100000) != 0
247         g_string_append_printf(str, " build %d",
248                                _MSC_FULL_VER % 100000);
249 #  endif
250 # else
251         g_string_append_printf(str, "\n\nBuilt using Microsoft Visual C++ %d.%d",
252                                (_MSC_FULL_VER / 1000000) - 6,
253                                (_MSC_FULL_VER / 10000) % 100);
254 #  if (_MSC_FULL_VER % 10000) != 0
255         g_string_append_printf(str, " build %d",
256                                _MSC_FULL_VER % 10000);
257 #  endif
258 # endif
259         g_string_append_printf(str, "\n");
260 #elif defined(_MSC_VER)
261         /* _MSC_FULL_VER not defined, but _MSC_VER defined */
262         g_string_append_printf(str, "\n\nBuilt using Microsoft Visual C++ %d.%d\n",
263             (_MSC_VER / 100) - 6, _MSC_VER % 100);
264 #elif defined(__SUNPRO_C)
265         g_string_append_printf(str, "\n\nBuilt using Sun C %d.%d",
266             (__SUNPRO_C >> 8) & 0xF, (__SUNPRO_C >> 4) & 0xF);
267         if ((__SUNPRO_C & 0xF) != 0)
268                 g_string_append_printf(str, " patch %d", __SUNPRO_C & 0xF);
269         g_string_append_printf(str, "\n");
270 #endif
271 }
272
273 /* XXX - is the setlocale() return string opaque? For glibc the separator is ';' */
274 static gchar *
275 get_locale(void)
276 {
277         const gchar *lang;
278         gchar **locv, *loc;
279
280         lang = setlocale(LC_ALL, NULL);
281         if (lang == NULL) {
282                 return NULL;
283         }
284
285         locv = g_strsplit(lang, ";", -1);
286         loc = g_strjoinv(", ", locv);
287         g_strfreev(locv);
288         return loc;
289 }
290
291 /*
292  * Get various library run-time versions, and the OS version, and append
293  * them to the specified GString.
294  *
295  * "additional_info" is called at the end to append any additional
296  * information; this is required in order to, for example, put the
297  * Portaudio information at the end of the string, as we currently
298  * don't use Portaudio in TShark.
299  */
300 GString *
301 get_runtime_version_info(void (*additional_info)(GString *))
302 {
303         GString *str;
304         gchar *lang;
305
306         str = g_string_new("Running on ");
307
308         get_os_version_info(str);
309
310         /* CPU Info */
311         get_cpu_info(str);
312
313         /* Get info about installed memory */
314         get_mem_info(str);
315
316         /*
317          * Locale.
318          *
319          * This returns the C language's locale information; this
320          * returns the locale that's actually in effect, even if
321          * it doesn't happen to match the settings of any of the
322          * locale environment variables.
323          *
324          * On Windows get_locale returns the full language, country
325          * name, and code page, e.g. "English_United States.1252":
326          * https://msdn.microsoft.com/en-us/library/x99tb11d.aspx
327          */
328         if ((lang = get_locale()) != NULL) {
329                 g_string_append_printf(str, ", with locale %s", lang);
330                 g_free(lang);
331         }
332         else {
333                 g_string_append(str, ", with default locale");
334         }
335
336
337         /* Additional application-dependent information */
338         if (additional_info)
339                 (*additional_info)(str);
340
341         /* zlib */
342 #if defined(HAVE_ZLIB) && !defined(_WIN32)
343         g_string_append_printf(str, ", with zlib %s", zlibVersion());
344 #endif
345
346         g_string_append(str, ".");
347
348         /* Compiler info */
349         get_compiler_info(str);
350
351         end_string(str);
352
353         return str;
354 }
355
356 void
357 show_version(const gchar *prog_name_str, GString *comp_info_str,
358              GString *runtime_info_str)
359 {
360         ws_debug_printf("%s %s\n"
361                "\n"
362                "%s"
363                "\n"
364                "%s"
365                "\n"
366                "%s",
367                prog_name_str, get_ws_vcs_version_info(), get_copyright_info(),
368                comp_info_str->str, runtime_info_str->str);
369 }
370
371 /*
372  * Return a version number string for Wireshark, including, for builds
373  * from a tree checked out from Wireshark's version control system,
374  * something identifying what version was checked out.
375  */
376 const char *
377 get_ws_vcs_version_info(void)
378 {
379 #ifdef VCSVERSION
380         return VERSION " (" VCSVERSION ")";
381 #else
382         return VERSION;
383 #endif
384 }
385
386 /*
387  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
388  *
389  * Local variables:
390  * c-basic-offset: 8
391  * tab-width: 8
392  * indent-tabs-mode: t
393  * End:
394  *
395  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
396  * :indentSize=8:tabSize=8:noTabs=false:
397  */