The Battle for Wesnoth  1.15.0-dev
version.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2015 - 2018 by Iris Morelle <shadowm2006@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "desktop/version.hpp"
18 
19 #include "filesystem.hpp"
20 #include "formatter.hpp"
21 #include "gettext.hpp"
22 #include "log.hpp"
24 
25 #include <cstring>
26 
27 #if defined(__APPLE__)
28 
29 #include "apple_version.hpp"
30 
31 #elif defined(_X11)
32 
33 #include <cerrno>
34 #include <sys/utsname.h>
35 
36 #endif
37 
38 #ifdef _WIN32
39 
40 #ifndef UNICODE
41 #define UNICODE
42 #endif
43 #define WIN32_LEAN_AND_MEAN
44 
45 #include <windows.h>
46 
47 #endif
48 
49 static lg::log_domain log_desktop("desktop");
50 #define ERR_DU LOG_STREAM(err, log_desktop)
51 #define LOG_DU LOG_STREAM(info, log_desktop)
52 
53 namespace desktop
54 {
55 
56 namespace
57 {
58 
59 #ifdef _WIN32
60 /**
61  * Detects whether we are running on Wine or not.
62  *
63  * This is for informational purposes only and all Windows code should assume
64  * we are running on the real thing instead.
65  */
66 bool on_wine()
67 {
68  HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
69  if(!ntdll) {
70  return false;
71  }
72 
73  return GetProcAddress(ntdll, "wine_get_version") != nullptr;
74 }
75 #endif
76 
77 #if defined(_X11)
78 /**
79  * Release policy for POSIX pipe streams opened with popen(3).
80  */
81 struct posix_pipe_release_policy
82 {
83  void operator()(std::FILE* f) const { if(f != nullptr) { pclose(f); } }
84 };
85 
86 /**
87  * Scoped POSIX pipe stream.
88  *
89  * The stream object type is the same as a regular file stream, but the release
90  * policy is different, as required by popen(3).
91  */
92 typedef std::unique_ptr<std::FILE, posix_pipe_release_policy> scoped_posix_pipe;
93 
94 /**
95  * Read a single line from the specified pipe.
96  *
97  * @returns An empty string if the pipe is invalid or nothing could be read.
98  */
99 std::string read_pipe_line(scoped_posix_pipe& p)
100 {
101  if(!p.get()) {
102  return "";
103  }
104 
105  std::string ver;
106  int c;
107 
108  ver.reserve(64);
109 
110  // We only want the first line.
111  while((c = std::fgetc(p.get())) && c != EOF && c != '\n' && c != '\r') {
112  ver.push_back(static_cast<char>(c));
113  }
114 
115  return ver;
116 }
117 #endif
118 
119 } // end anonymous namespace
120 
121 std::string os_version()
122 {
123 #if defined(__APPLE__)
124 
125  //
126  // Standard Mac OS X version
127  //
128 
130 
131 #elif defined(_X11)
132 
133  //
134  // Linux Standard Base version.
135  //
136 
137  static const std::string lsb_release_bin = "/usr/bin/lsb_release";
138 
139  if(filesystem::file_exists(lsb_release_bin)) {
140  static const std::string cmdline = lsb_release_bin + " -s -d";
141 
142  scoped_posix_pipe p(popen(cmdline.c_str(), "r"));
143  std::string ver = read_pipe_line(p);
144 
145  if(ver.length() >= 2 && ver[0] == '"' && ver[ver.length() - 1] == '"') {
146  ver.erase(ver.length() - 1, 1);
147  ver.erase(0, 1);
148  }
149 
150  // Check this again in case we got "" above for some weird reason.
151  if(!ver.empty()) {
152  return ver;
153  }
154  }
155 
156  //
157  // POSIX uname version fallback.
158  //
159 
160  utsname u;
161 
162  if(uname(&u) != 0) {
163  ERR_DU << "os_version: uname error (" << strerror(errno) << ")\n";
164  }
165 
166  return formatter() << u.sysname << ' '
167  << u.release << ' '
168  << u.version << ' '
169  << u.machine;
170 
171 #elif defined(_WIN32)
172 
173  //
174  // Windows version.
175  //
176 
177  static const std::string base
178  = !on_wine() ? "Microsoft Windows" : "Wine/Microsoft Windows";
179 
180  OSVERSIONINFOEX v { sizeof(OSVERSIONINFOEX) };
181 
182 #ifdef _MSC_VER
183 // GetVersionEx is rather problematic, but it works for our usecase.
184 // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx
185 // for more info.
186 #pragma warning(push)
187 #pragma warning(disable:4996)
188 #endif
189  if(!GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&v))) {
190  ERR_DU << "os_version: GetVersionEx error ("
191  << GetLastError() << ")\n";
192  return base;
193  }
194 #ifdef _MSC_VER
195 #pragma warning(pop)
196 #endif
197 
198  const DWORD vnum = v.dwMajorVersion * 100 + v.dwMinorVersion;
199  std::string version;
200 
201  switch(vnum)
202  {
203  case 500:
204  version = "2000";
205  break;
206  case 501:
207  version = "XP";
208  break;
209  case 502:
210  // This will misidentify XP x64 but who really cares?
211  version = "Server 2003";
212  break;
213  case 600:
214  if(v.wProductType == VER_NT_WORKSTATION) {
215  version = "Vista";
216  } else {
217  version = "Server 2008";
218  }
219  break;
220  case 601:
221  if(v.wProductType == VER_NT_WORKSTATION) {
222  version = "7";
223  } else {
224  version = "Server 2008 R2";
225  }
226  break;
227  case 602:
228  if(v.wProductType == VER_NT_WORKSTATION) {
229  version = "8";
230  } else {
231  version = "Server 2012";
232  }
233  break;
234  case 603:
235  if(v.wProductType == VER_NT_WORKSTATION) {
236  version = "8.1";
237  } else {
238  version = "Server 2012 R2";
239  }
240  break;
241  case 1000:
242  if(v.wProductType == VER_NT_WORKSTATION) {
243  version = "10";
244  break;
245  } // else fallback to default
246  default:
247  if(v.wProductType != VER_NT_WORKSTATION) {
248  version = "Server";
249  }
250  }
251 
252  if(v.szCSDVersion && *v.szCSDVersion) {
253  version += " ";
254  version += unicode_cast<std::string>(std::wstring(v.szCSDVersion));
255  }
256 
257  version += " (";
258  // Add internal version numbers.
259  version += formatter()
260  << v.dwMajorVersion << '.'
261  << v.dwMinorVersion << '.'
262  << v.dwBuildNumber;
263  version += ")";
264 
265  return base + " " + version;
266 
267 #else
268 
269  //
270  // "I don't know where I am" version.
271  //
272 
273  ERR_DU << "os_version(): unsupported platform\n";
274  return _("operating_system^<unknown>");
275 
276 #endif
277 }
278 
279 } // end namespace desktop
#define ERR_DU
Definition: version.cpp:50
static bool file_exists(const fs::path &fpath)
Definition: filesystem.cpp:300
ucs4_convert_impl::enableif< TD, typename TS::value_type >::type unicode_cast(const TS &source)
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
std::ostringstream wrapper.
Definition: formatter.hpp:38
Platform identification and version information functions.
std::string os_version()
Returns a string with the running OS name and version information.
Definition: version.cpp:121
mock_party p
std::string os_version()
Returns a string with the running OS name and version information.
Definition: version.cpp:121
Declarations for File-IO.
static lg::log_domain log_desktop("desktop")
#define f
Standard logging facilities (interface).
mock_char c