Scarab  v2.2.3
Project 8 C++ Utility Library
version_base.cc
Go to the documentation of this file.
1 /*
2  * version_base.cc
3  *
4  * Created on: Jul 23, 2018
5  * Author: N.S. Oblath
6  */
7 
8 #include "version_base.hh"
9 
10 #include "logger.hh"
11 #include "path.hh"
12 
13 #include <sstream>
14 
15 #ifdef _WIN32
16 #include <Windows.h> // for extracting the exe name, gethostname and GetUserName
17 #elif __APPLE__
18 #include <mach-o/dyld.h> // for extracting the exe name
19 #include <unistd.h> // for gethostname and getlogin_r
20 #include <pwd.h> // for struct passwd
21 #elif __linux
22 #include <unistd.h> // for readlink, gethostname and getlogin_r
23 #include <pwd.h> // for struct passwd
24 #endif
25 
26 using std::string;
27 
28 namespace scarab
29 {
30  LOGGER( slog, "scarab_version" );
31 
33  {}
34 
36  {}
37 
39  {}
40 
42  {
43  return *this;
44  }
45 
46 
48 
50  version_ifc(),
51  f_major_ver(),
52  f_minor_ver(),
53  f_patch_ver(),
54  f_version(),
55  f_package(),
56  f_commit(),
57  f_exe_name(),
58  f_hostname(),
59  f_username()
60  {
62  }
63 
64  version_semantic::version_semantic( unsigned a_maj_ver, unsigned a_min_ver, unsigned a_patch_ver ) :
65  version_ifc(),
66  f_major_ver( a_maj_ver ),
67  f_minor_ver( a_min_ver ),
68  f_patch_ver( a_patch_ver ),
69  f_version(),
70  f_package(),
71  f_commit(),
72  f_exe_name(),
73  f_hostname(),
74  f_username()
75  {
76  combine( a_maj_ver, a_min_ver, a_patch_ver );
78  }
79 
80  version_semantic::version_semantic( const std::string& a_ver ) :
81  version_ifc(),
82  f_major_ver( 0 ),
83  f_minor_ver( 0 ),
84  f_patch_ver( 0 ),
85  f_version( a_ver ),
86  f_package(),
87  f_commit(),
88  f_exe_name(),
89  f_hostname(),
90  f_username()
91  {
92  parse( a_ver );
94  }
95 
97  version_ifc(),
98  f_major_ver( a_orig.f_major_ver ),
99  f_minor_ver( a_orig.f_minor_ver ),
100  f_patch_ver( a_orig.f_patch_ver ),
101  f_version( a_orig.f_version ),
102  f_package( a_orig.f_package ),
103  f_commit( a_orig.f_commit ),
104  f_exe_name( a_orig.f_exe_name ),
105  f_hostname( a_orig.f_hostname ),
106  f_username( a_orig.f_username )
107  {
108  }
109 
111  {
112  }
113 
115  {
116  this->version_ifc::operator=( a_orig );
117  f_major_ver = a_orig.f_major_ver;
118  f_minor_ver = a_orig.f_minor_ver;
119  f_patch_ver = a_orig.f_patch_ver;
120  f_version = a_orig.f_version;
121  f_package = a_orig.f_package;
122  f_commit = a_orig.f_commit;
123  f_exe_name = a_orig.f_exe_name;
124  f_hostname = a_orig.f_hostname;
125  f_username = a_orig.f_username;
126  return *this;
127  }
128 
130  {
131  if( f_major_ver < a_other.f_major_ver ) return true;
132  if( f_minor_ver < a_other.f_minor_ver ) return true;
133  if( f_patch_ver < a_other.f_patch_ver ) return true;
134  return false;
135  }
136 
138  {
139  return f_major_ver == a_other.f_major_ver &&
140  f_minor_ver == a_other.f_minor_ver &&
141  f_patch_ver == a_other.f_patch_ver;
142  }
143 
144  bool version_semantic::parse( const std::string& a_ver )
145  {
146  if( a_ver == "unknown" )
147  {
148  f_major_ver = 0;
149  f_minor_ver = 0;
150  f_patch_ver = 0;
151  f_version = a_ver;
152  return true;
153  }
154 
155  size_t t_delim_pos_1 = a_ver.find( s_delimeter, 0 );
156  if( t_delim_pos_1 == std::string::npos )
157  {
158  LERROR( slog, "version string <" << a_ver << "> is not in the right format (did not find first delimeter)" );
159  return false;
160  }
161  std::stringstream t_maj_ver_str;
162  t_maj_ver_str << a_ver.substr( 0, t_delim_pos_1 );
163 
164  size_t t_delim_pos_2 = a_ver.find( s_delimeter, t_delim_pos_1 + 1 );
165  if( t_delim_pos_2 == std::string::npos )
166  {
167  LERROR( slog, "version string <" << a_ver << "> is not in the right format (did not find second delimeter)" );
168  return false;
169  }
170  std::stringstream t_min_ver_str;
171  t_min_ver_str << a_ver.substr(t_delim_pos_1 + 1, t_delim_pos_2 );
172 
173  std::stringstream t_patch_ver;
174  t_patch_ver << a_ver.substr( t_delim_pos_2 + 1 );
175 
176  t_maj_ver_str >> f_major_ver;
177  t_min_ver_str >> f_minor_ver;
178  t_patch_ver >> f_patch_ver;
179  f_version = a_ver;
180 
181  return true;
182  }
183 
184  bool version_semantic::combine( unsigned a_maj_ver, unsigned a_min_ver, unsigned a_patch_ver )
185  {
186  std::stringstream t_ver_str;
187  t_ver_str << a_maj_ver << s_delimeter << a_min_ver << s_delimeter << a_patch_ver;
188  f_version = t_ver_str.str();
189  return true;
190  }
191 
193  {
194  const size_t t_bufsize = 1024;
195 
196  // Username
197 #ifdef _WIN32
198  char t_username_buf[ t_bufsize ];
199  DWORD t_bufsize_win = t_bufsize;
200  if( GetUserName( t_username_buf, &t_bufsize_win ) )
201  {
202  f_username = string( t_username_buf );
203  }
204  else
205  {
206 #else
207  //if( getlogin_r( t_username_buf, t_bufsize ) == 0 )
208  passwd* t_passwd = getpwuid( getuid() );
209  if( t_passwd != nullptr )
210  {
211  f_username = string( t_passwd->pw_name );
212  }
213  else
214  {
215  LWARN( slog, "Error reported while getting passwd info: " << strerror( errno ) );
216 #endif
217  LWARN( slog, "Unable to get the username" );
218  }
219 
220  // Hostname
221  char t_hostname_buf[ t_bufsize ];
222 #ifdef _WIN32
223  WSADATA wsaData;
224  WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
225 #endif
226  // gethostname is the same on posix and windows
227  if( gethostname( t_hostname_buf, t_bufsize ) == 0 )
228  {
229  f_hostname = string( t_hostname_buf );
230  }
231  else
232  {
233  LWARN( slog, "Unable to get the hostname" );
234  }
235 #ifdef _WIN32
236  WSACleanup();
237 #endif
238 
239  // name of executable
240  //f_exe_name = t_parser.get_value( t_name_exe, f_exe_name );
241 #ifdef _WIN32
242  TCHAR t_exe_buf[ MAX_PATH ];
243  if( ! GetModuleFileName( NULL, t_exe_buf, MAX_PATH ) )
244 #elif __APPLE__
245  char t_exe_buf[ 2048 ];
246  uint32_t t_exe_bufsize = sizeof( t_exe_buf );
247  if( _NSGetExecutablePath( t_exe_buf, &t_exe_bufsize ) != 0 )
248 #elif __linux
249  const size_t t_exe_bufsize = 2048;
250  char t_exe_buf[ t_exe_bufsize ];
251  ssize_t t_exe_name_len = readlink( "/proc/self/exe", t_exe_buf, t_exe_bufsize );
252  if( t_exe_name_len >= 0 )
253  {
254  t_exe_buf[t_exe_name_len] = '\0';
255  }
256  else
257  //if( readlink( "/proc/self/exe", t_exe_buf, t_exe_bufsize ) < 0 )
258 #endif
259  {
260  LWARN( slog, "Could not retrieve executable file name" );
261 #ifdef __APPLE__
262  LWARN( slog, "Executable name buffer is too small; needs size %u\n" << t_bufsize );
263 #endif
264  }
265  f_exe_name = string( t_exe_buf );
266 
267  return true;
268  }
269 
271  {
272  std::stringstream t_info_stream;
273  path t_exe_path( f_exe_name );
274  t_info_stream << "Executable: " << t_exe_path.filename() << '\n';
275  t_info_stream << "Location: " << t_exe_path.parent_path() << '\n';
276  t_info_stream << "Built with " << f_package << " version " << f_version << '\n';
277  t_info_stream << "Git commit: " << f_commit;
278  std::string t_version_info( t_info_stream.str() );
279  return t_version_info;
280  }
281 
282 } /* namespace scarab */
#define LWARN(...)
Definition: logger.hh:364
fs::path path
Definition: path.hh:25
version_ifc & operator=(const version_ifc &)
Definition: version_base.cc:41
bool combine(unsigned a_maj_ver, unsigned a_min_ver, unsigned a_patch_ver)
#define LERROR(...)
Definition: logger.hh:365
bool operator<(const version_semantic &a_other)
Less-than operator to compare version information only.
version_semantic & operator=(const version_semantic &a_orig)
Contains the logger class and macros, based on Kasper&#39;s KLogger class.
bool operator==(const version_semantic &a_other)
Equality operator to compare version information only.
virtual ~version_ifc()
Definition: version_base.cc:38
bool parse(const std::string &a_ver)
virtual std::string version_info_string() const
LOGGER(mtlog,"authentication")