Electroneum
Loading...
Searching...
No Matches
util.cpp
Go to the documentation of this file.
1// Copyrights(c) 2017-2021, The Electroneum Project
2// Copyrights(c) 2014-2019, The Monero Project
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without modification, are
7// permitted provided that the following conditions are met:
8//
9// 1. Redistributions of source code must retain the above copyright notice, this list of
10// conditions and the following disclaimer.
11//
12// 2. Redistributions in binary form must reproduce the above copyright notice, this list
13// of conditions and the following disclaimer in the documentation and/or other
14// materials provided with the distribution.
15//
16// 3. Neither the name of the copyright holder nor the names of its contributors may be
17// used to endorse or promote products derived from this software without specific
18// prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31
32#include <unistd.h>
33#include <cstdio>
34
35#ifdef __GLIBC__
36#include <gnu/libc-version.h>
37#endif
38
39#ifdef __GLIBC__
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <sys/resource.h>
43#include <unistd.h>
44#include <dirent.h>
45#include <string.h>
46#include <ctype.h>
47#include <string>
48#endif
49
50//tools::is_hdd
51#ifdef __GLIBC__
52 #include <sstream>
53 #include <sys/sysmacros.h>
54 #include <fstream>
55#endif
56
57#include "unbound.h"
58
59#include "include_base_utils.h"
60#include "file_io_utils.h"
61#include "wipeable_string.h"
62#include "misc_os_dependent.h"
63using namespace epee;
64
65#include "crypto/crypto.h"
66#include "util.h"
67#include "stack_trace.h"
68#include "memwipe.h"
69#include "cryptonote_config.h"
70#include "net/http_client.h" // epee::net_utils::...
71
72#ifdef WIN32
73#ifndef STRSAFE_NO_DEPRECATE
74#define STRSAFE_NO_DEPRECATE
75#endif
76 #include <windows.h>
77 #include <shlobj.h>
78 #include <strsafe.h>
79#else
80 #include <sys/file.h>
81 #include <sys/utsname.h>
82 #include <sys/stat.h>
83#endif
84#include <boost/filesystem.hpp>
85#include <boost/algorithm/string.hpp>
86#include <boost/asio.hpp>
87#include <boost/format.hpp>
88#include <openssl/sha.h>
89
90#undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
91#define ELECTRONEUM_DEFAULT_LOG_CATEGORY "util"
92
93namespace
94{
95
96#ifndef _WIN32
97static int flock_exnb(int fd)
98{
99 struct flock fl;
100 int ret;
101
102 memset(&fl, 0, sizeof(fl));
103 fl.l_type = F_WRLCK;
104 fl.l_whence = SEEK_SET;
105 fl.l_start = 0;
106 fl.l_len = 0;
107 ret = fcntl(fd, F_SETLK, &fl);
108 if (ret < 0)
109 MERROR("Error locking fd " << fd << ": " << errno << " (" << strerror(errno) << ")");
110 return ret;
111}
112#endif
113
114}
115
116namespace tools
117{
118 std::function<void(int)> signal_handler::m_handler;
119
120 private_file::private_file() noexcept : m_handle(), m_filename() {}
121
122 private_file::private_file(std::FILE* handle, std::string&& filename) noexcept
123 : m_handle(handle), m_filename(std::move(filename)) {}
124
125 private_file private_file::create(std::string name)
126 {
127#ifdef WIN32
128 struct close_handle
129 {
130 void operator()(HANDLE handle) const noexcept
131 {
132 CloseHandle(handle);
133 }
134 };
135
136 std::unique_ptr<void, close_handle> process = nullptr;
137 {
138 HANDLE temp{};
139 const bool fail = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, std::addressof(temp)) == 0;
140 process.reset(temp);
141 if (fail)
142 return {};
143 }
144
145 DWORD sid_size = 0;
146 GetTokenInformation(process.get(), TokenOwner, nullptr, 0, std::addressof(sid_size));
147 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
148 return {};
149
150 std::unique_ptr<char[]> sid{new char[sid_size]};
151 if (!GetTokenInformation(process.get(), TokenOwner, sid.get(), sid_size, std::addressof(sid_size)))
152 return {};
153
154 const PSID psid = reinterpret_cast<const PTOKEN_OWNER>(sid.get())->Owner;
155 const DWORD daclSize =
156 sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD);
157
158 const std::unique_ptr<char[]> dacl{new char[daclSize]};
159 if (!InitializeAcl(reinterpret_cast<PACL>(dacl.get()), daclSize, ACL_REVISION))
160 return {};
161
162 if (!AddAccessAllowedAce(reinterpret_cast<PACL>(dacl.get()), ACL_REVISION, (READ_CONTROL | FILE_GENERIC_READ | DELETE), psid))
163 return {};
164
165 SECURITY_DESCRIPTOR descriptor{};
166 if (!InitializeSecurityDescriptor(std::addressof(descriptor), SECURITY_DESCRIPTOR_REVISION))
167 return {};
168
169 if (!SetSecurityDescriptorDacl(std::addressof(descriptor), true, reinterpret_cast<PACL>(dacl.get()), false))
170 return {};
171
172 SECURITY_ATTRIBUTES attributes{sizeof(SECURITY_ATTRIBUTES), std::addressof(descriptor), false};
173 std::unique_ptr<void, close_handle> file{
174 CreateFile(
175 name.c_str(),
176 GENERIC_WRITE, FILE_SHARE_READ,
177 std::addressof(attributes),
178 CREATE_NEW, (FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE),
179 nullptr
180 )
181 };
182 if (file)
183 {
184 const int fd = _open_osfhandle(reinterpret_cast<intptr_t>(file.get()), 0);
185 if (0 <= fd)
186 {
187 file.release();
188 std::FILE* real_file = _fdopen(fd, "w");
189 if (!real_file)
190 {
191 _close(fd);
192 }
193 return {real_file, std::move(name)};
194 }
195 }
196#else
197 const int fdr = open(name.c_str(), (O_RDONLY | O_CREAT), S_IRUSR);
198 if (0 <= fdr)
199 {
200 struct stat rstats = {};
201 if (fstat(fdr, std::addressof(rstats)) != 0)
202 {
203 close(fdr);
204 return {};
205 }
206 fchmod(fdr, (S_IRUSR | S_IWUSR));
207 const int fdw = open(name.c_str(), O_RDWR);
208 fchmod(fdr, rstats.st_mode);
209 close(fdr);
210
211 if (0 <= fdw)
212 {
213 struct stat wstats = {};
214 if (fstat(fdw, std::addressof(wstats)) == 0 &&
215 rstats.st_dev == wstats.st_dev && rstats.st_ino == wstats.st_ino &&
216 flock_exnb(fdw) == 0 && ftruncate(fdw, 0) == 0)
217 {
218 std::FILE* file = fdopen(fdw, "w");
219 if (file) return {file, std::move(name)};
220 }
221 close(fdw);
222 }
223 }
224#endif
225 return {};
226 }
227
229 {
230 try
231 {
232 boost::system::error_code ec{};
233 boost::filesystem::remove(filename(), ec);
234 }
235 catch (...) {}
236 }
237
238 file_locker::file_locker(const std::string &filename)
239 {
240#ifdef WIN32
241 m_fd = INVALID_HANDLE_VALUE;
242 std::wstring filename_wide;
243 try
244 {
245 filename_wide = string_tools::utf8_to_utf16(filename);
246 }
247 catch (const std::exception &e)
248 {
249 MERROR("Failed to convert path \"" << filename << "\" to UTF-16: " << e.what());
250 return;
251 }
252 m_fd = CreateFileW(filename_wide.c_str(), GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
253 if (m_fd != INVALID_HANDLE_VALUE)
254 {
255 OVERLAPPED ov;
256 memset(&ov, 0, sizeof(ov));
257 if (!LockFileEx(m_fd, LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ov))
258 {
259 MERROR("Failed to lock " << filename << ": " << std::error_code(GetLastError(), std::system_category()));
260 CloseHandle(m_fd);
261 m_fd = INVALID_HANDLE_VALUE;
262 }
263 }
264 else
265 {
266 MERROR("Failed to open " << filename << ": " << std::error_code(GetLastError(), std::system_category()));
267 }
268#else
269 m_fd = open(filename.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0666);
270 if (m_fd != -1)
271 {
272 if (flock_exnb(m_fd) == -1)
273 {
274 MERROR("Failed to lock " << filename << ": " << std::strerror(errno));
275 close(m_fd);
276 m_fd = -1;
277 }
278 }
279 else
280 {
281 MERROR("Failed to open " << filename << ": " << std::strerror(errno));
282 }
283#endif
284 }
286 {
287 if (locked())
288 {
289#ifdef WIN32
290 CloseHandle(m_fd);
291#else
292 close(m_fd);
293#endif
294 }
295 }
297 {
298#ifdef WIN32
299 return m_fd != INVALID_HANDLE_VALUE;
300#else
301 return m_fd != -1;
302#endif
303 }
304
305#ifdef WIN32
306 std::string get_windows_version_display_string()
307 {
308 typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
309 typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
310#define BUFSIZE 10000
311
312 char pszOS[BUFSIZE] = {0};
313 OSVERSIONINFOEX osvi;
314 SYSTEM_INFO si;
315 PGNSI pGNSI;
316 PGPI pGPI;
317 BOOL bOsVersionInfoEx;
318 DWORD dwType;
319
320 ZeroMemory(&si, sizeof(SYSTEM_INFO));
321 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
322
323 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
324 bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);
325
326 if(!bOsVersionInfoEx) return pszOS;
327
328 // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
329
330 pGNSI = (PGNSI) GetProcAddress(
331 GetModuleHandle(TEXT("kernel32.dll")),
332 "GetNativeSystemInfo");
333 if(NULL != pGNSI)
334 pGNSI(&si);
335 else GetSystemInfo(&si);
336
337 if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId &&
338 osvi.dwMajorVersion > 4 )
339 {
340 StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft "));
341
342 // Test for the specific product.
343 if ( osvi.dwMajorVersion == 10 )
344 {
345 if ( osvi.dwMinorVersion == 0 )
346 {
347 if( osvi.wProductType == VER_NT_WORKSTATION )
348 StringCchCat(pszOS, BUFSIZE, TEXT("Windows 10 "));
349 else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2016 " ));
350 }
351 }
352
353 if ( osvi.dwMajorVersion == 6 )
354 {
355 if ( osvi.dwMinorVersion == 0 )
356 {
357 if( osvi.wProductType == VER_NT_WORKSTATION )
358 StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista "));
359 else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 " ));
360 }
361
362 if ( osvi.dwMinorVersion == 1 )
363 {
364 if( osvi.wProductType == VER_NT_WORKSTATION )
365 StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 "));
366 else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 " ));
367 }
368
369 if ( osvi.dwMinorVersion == 2 )
370 {
371 if( osvi.wProductType == VER_NT_WORKSTATION )
372 StringCchCat(pszOS, BUFSIZE, TEXT("Windows 8 "));
373 else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2012 " ));
374 }
375
376 if ( osvi.dwMinorVersion == 3 )
377 {
378 if( osvi.wProductType == VER_NT_WORKSTATION )
379 StringCchCat(pszOS, BUFSIZE, TEXT("Windows 8.1 "));
380 else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2012 R2 " ));
381 }
382
383 pGPI = (PGPI) GetProcAddress(
384 GetModuleHandle(TEXT("kernel32.dll")),
385 "GetProductInfo");
386
387 pGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
388
389 switch( dwType )
390 {
391 case PRODUCT_ULTIMATE:
392 StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" ));
393 break;
394 case PRODUCT_PROFESSIONAL:
395 StringCchCat(pszOS, BUFSIZE, TEXT("Professional" ));
396 break;
397 case PRODUCT_HOME_PREMIUM:
398 StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" ));
399 break;
400 case PRODUCT_HOME_BASIC:
401 StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" ));
402 break;
403 case PRODUCT_ENTERPRISE:
404 StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
405 break;
406 case PRODUCT_BUSINESS:
407 StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" ));
408 break;
409 case PRODUCT_STARTER:
410 StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" ));
411 break;
412 case PRODUCT_CLUSTER_SERVER:
413 StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" ));
414 break;
415 case PRODUCT_DATACENTER_SERVER:
416 StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" ));
417 break;
418 case PRODUCT_DATACENTER_SERVER_CORE:
419 StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" ));
420 break;
421 case PRODUCT_ENTERPRISE_SERVER:
422 StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
423 break;
424 case PRODUCT_ENTERPRISE_SERVER_CORE:
425 StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" ));
426 break;
427 case PRODUCT_ENTERPRISE_SERVER_IA64:
428 StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" ));
429 break;
430 case PRODUCT_SMALLBUSINESS_SERVER:
431 StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" ));
432 break;
433 case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
434 StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" ));
435 break;
436 case PRODUCT_STANDARD_SERVER:
437 StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" ));
438 break;
439 case PRODUCT_STANDARD_SERVER_CORE:
440 StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" ));
441 break;
442 case PRODUCT_WEB_SERVER:
443 StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" ));
444 break;
445 }
446 }
447
448 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
449 {
450 if( GetSystemMetrics(SM_SERVERR2) )
451 StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, "));
452 else if ( osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER )
453 StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003"));
454 else if ( osvi.wSuiteMask & VER_SUITE_WH_SERVER )
455 StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server"));
456 else if( osvi.wProductType == VER_NT_WORKSTATION &&
457 si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
458 {
459 StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition"));
460 }
461 else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, "));
462
463 // Test for the server type.
464 if ( osvi.wProductType != VER_NT_WORKSTATION )
465 {
466 if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
467 {
468 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
469 StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" ));
470 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
471 StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" ));
472 }
473
474 else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
475 {
476 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
477 StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" ));
478 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
479 StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" ));
480 else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" ));
481 }
482
483 else
484 {
485 if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
486 StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" ));
487 else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
488 StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" ));
489 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
490 StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" ));
491 else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
492 StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" ));
493 else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" ));
494 }
495 }
496 }
497
498 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
499 {
500 StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP "));
501 if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
502 StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" ));
503 else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
504 }
505
506 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
507 {
508 StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 "));
509
510 if ( osvi.wProductType == VER_NT_WORKSTATION )
511 {
512 StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
513 }
514 else
515 {
516 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
517 StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" ));
518 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
519 StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" ));
520 else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" ));
521 }
522 }
523
524 // Include service pack (if any) and build number.
525
526 if( strlen(osvi.szCSDVersion) > 0 )
527 {
528 StringCchCat(pszOS, BUFSIZE, TEXT(" ") );
529 StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion);
530 }
531
532 TCHAR buf[80];
533
534 StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber);
535 StringCchCat(pszOS, BUFSIZE, buf);
536
537 if ( osvi.dwMajorVersion >= 6 )
538 {
539 if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
540 StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" ));
541 else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
542 StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit"));
543 }
544
545 return pszOS;
546 }
547 else
548 {
549 printf( "This sample does not support this version of Windows.\n");
550 return pszOS;
551 }
552 }
553#else
555{
556 struct utsname un;
557
558 if(uname(&un) < 0)
559 return std::string("*nix: failed to get os version");
560 return std::string() + un.sysname + " " + un.version + " " + un.release;
561}
562#endif
563
564
565
567 {
568#ifdef WIN32
569 return get_windows_version_display_string();
570#else
572#endif
573 }
574
575
576
577#ifdef WIN32
578 std::string get_special_folder_path(int nfolder, bool iscreate)
579 {
580 WCHAR psz_path[MAX_PATH] = L"";
581
582 if (SHGetSpecialFolderPathW(NULL, psz_path, nfolder, iscreate))
583 {
584 try
585 {
586 return string_tools::utf16_to_utf8(psz_path);
587 }
588 catch (const std::exception &e)
589 {
590 MERROR("utf16_to_utf8 failed: " << e.what());
591 return "";
592 }
593 }
594
595 LOG_ERROR("SHGetSpecialFolderPathW() failed, could not obtain requested path.");
596 return "";
597 }
598#endif
599
601 {
602 /* Please for the love of god refactor the ifdefs out of this */
603
604 // namespace fs = boost::filesystem;
605 // Windows < Vista: C:\Documents and Settings\Username\Application Data\CRYPTONOTE_NAME
606 // Windows >= Vista: C:\Users\Username\AppData\Roaming\CRYPTONOTE_NAME
607 // Unix & Mac: ~/.CRYPTONOTE_NAME
608 std::string config_folder;
609
610#ifdef WIN32
611 config_folder = get_special_folder_path(CSIDL_COMMON_APPDATA, true) + "\\" + CRYPTONOTE_NAME;
612#else
613 std::string pathRet;
614 char* pszHome = getenv("HOME");
615 if (pszHome == NULL || strlen(pszHome) == 0)
616 pathRet = "/";
617 else
618 pathRet = pszHome;
619 config_folder = (pathRet + "/." + CRYPTONOTE_NAME);
620#endif
621
622 return config_folder;
623 }
624
625 bool create_directories_if_necessary(const std::string& path)
626 {
627 namespace fs = boost::filesystem;
628 boost::system::error_code ec;
629 fs::path fs_path(path);
630 if (fs::is_directory(fs_path, ec))
631 {
632 return true;
633 }
634
635 bool res = fs::create_directories(fs_path, ec);
636 if (res)
637 {
638 LOG_PRINT_L2("Created directory: " << path);
639 }
640 else
641 {
642 LOG_PRINT_L2("Can't create directory: " << path << ", err: "<< ec.message());
643 }
644
645 return res;
646 }
647
648 std::error_code replace_file(const std::string& old_name, const std::string& new_name)
649 {
650 int code;
651#if defined(WIN32)
652 // Maximizing chances for success
653 std::wstring wide_replacement_name;
654 try { wide_replacement_name = string_tools::utf8_to_utf16(old_name); }
655 catch (...) { return std::error_code(GetLastError(), std::system_category()); }
656 std::wstring wide_replaced_name;
657 try { wide_replaced_name = string_tools::utf8_to_utf16(new_name); }
658 catch (...) { return std::error_code(GetLastError(), std::system_category()); }
659
660 DWORD attributes = ::GetFileAttributesW(wide_replaced_name.c_str());
661 if (INVALID_FILE_ATTRIBUTES != attributes)
662 {
663 ::SetFileAttributesW(wide_replaced_name.c_str(), attributes & (~FILE_ATTRIBUTE_READONLY));
664 }
665
666 bool ok = 0 != ::MoveFileExW(wide_replacement_name.c_str(), wide_replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING);
667 code = ok ? 0 : static_cast<int>(::GetLastError());
668#else
669 bool ok = 0 == std::rename(old_name.c_str(), new_name.c_str());
670 code = ok ? 0 : errno;
671#endif
672 return std::error_code(code, std::system_category());
673 }
674
675 static bool unbound_built_with_threads()
676 {
677 ub_ctx *ctx = ub_ctx_create();
678 if (!ctx) return false; // cheat a bit, should not happen unless OOM
679 char *electroneum = strdup("electroneum"), *unbound = strdup("unbound");
680 ub_ctx_zone_add(ctx, electroneum, unbound); // this calls ub_ctx_finalize first, then errors out with UB_SYNTAX
681 free(unbound);
682 free(electroneum);
683 // if no threads, bails out early with UB_NOERROR, otherwise fails with UB_AFTERFINAL id already finalized
684 bool with_threads = ub_ctx_async(ctx, 1) != 0; // UB_AFTERFINAL is not defined in public headers, check any error
685 ub_ctx_delete(ctx);
686 MINFO("libunbound was built " << (with_threads ? "with" : "without") << " threads");
687 return with_threads;
688 }
689
691 {
692 // boost::filesystem throws for "invalid" locales, such as en_US.UTF-8, or kjsdkfs,
693 // so reset it here before any calls to it
694 try
695 {
696 boost::filesystem::path p {std::string("test")};
697 p /= std::string("test");
698 }
699 catch (...)
700 {
701#if defined(__MINGW32__) || defined(__MINGW__)
702 putenv("LC_ALL=C");
703 putenv("LANG=C");
704#else
705 setenv("LC_ALL", "C", 1);
706 setenv("LANG", "C", 1);
707#endif
708 return true;
709 }
710 return false;
711 }
712
713#ifdef STACK_TRACE
714#ifdef _WIN32
715 // https://stackoverflow.com/questions/1992816/how-to-handle-seg-faults-under-windows
716 static LONG WINAPI windows_crash_handler(PEXCEPTION_POINTERS pExceptionInfo)
717 {
718 tools::log_stack_trace("crashing");
719 exit(1);
720 return EXCEPTION_CONTINUE_SEARCH;
721 }
722 static void setup_crash_dump()
723 {
724 SetUnhandledExceptionFilter(windows_crash_handler);
725 }
726#else
727 static void posix_crash_handler(int signal)
728 {
729 tools::log_stack_trace(("crashing with fatal signal " + std::to_string(signal)).c_str());
730#ifdef NDEBUG
731 _exit(1);
732#else
733 abort();
734#endif
735 }
736 static void setup_crash_dump()
737 {
738 signal(SIGSEGV, posix_crash_handler);
739 signal(SIGBUS, posix_crash_handler);
740 signal(SIGILL, posix_crash_handler);
741 signal(SIGFPE, posix_crash_handler);
742 }
743#endif
744#else
745 static void setup_crash_dump() {}
746#endif
747
749 {
750#ifdef __GLIBC__
751 // disable core dumps in release mode
752 struct rlimit rlimit;
753 rlimit.rlim_cur = rlimit.rlim_max = 0;
754 if (setrlimit(RLIMIT_CORE, &rlimit))
755 {
756 MWARNING("Failed to disable core dumps");
757 return false;
758 }
759#endif
760 return true;
761 }
762
764 {
765#ifdef __GLIBC__
766 struct rlimit rlim;
767 if (getrlimit(RLIMIT_MEMLOCK, &rlim) < 0)
768 {
769 MERROR("Failed to determine the lockable memory limit");
770 return -1;
771 }
772 return rlim.rlim_cur;
773#else
774 return -1;
775#endif
776 }
777
779 {
780 mlog_configure("", true);
781
782 setup_crash_dump();
783
785
786#ifdef __GLIBC__
787 const char *ver = gnu_get_libc_version();
788 if (!strcmp(ver, "2.25"))
789 MCLOG_RED(el::Level::Warning, "global", "Running with glibc " << ver << ", hangs may occur - change glibc version if possible");
790#endif
791
792#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(LIBRESSL_VERSION_TEXT)
793 SSL_library_init();
794#else
795 OPENSSL_init_ssl(0, NULL);
796#endif
797
798 if (!unbound_built_with_threads())
799 MCLOG_RED(el::Level::Warning, "global", "libunbound was not built with threads enabled - crashes may occur");
800
801 return true;
802 }
804 {
805#if defined(__MINGW32__) || defined(__MINGW__)
806 // no clue about the odd one out
807#else
808 mode_t mode = strict ? 077 : 0;
809 umask(mode);
810#endif
811 }
812
813 boost::optional<bool> is_hdd(const char *file_path)
814 {
815#ifdef __GLIBC__
816 struct stat st;
817 std::string prefix;
818 if(stat(file_path, &st) == 0)
819 {
820 std::ostringstream s;
821 s << "/sys/dev/block/" << major(st.st_dev) << ":" << minor(st.st_dev);
822 prefix = s.str();
823 }
824 else
825 {
826 return boost::none;
827 }
828 std::string attr_path = prefix + "/queue/rotational";
829 std::ifstream f(attr_path, std::ios_base::in);
830 if(not f.is_open())
831 {
832 attr_path = prefix + "/../queue/rotational";
833 f.open(attr_path, std::ios_base::in);
834 if(not f.is_open())
835 {
836 return boost::none;
837 }
838 }
839 unsigned short val = 0xdead;
840 f >> val;
841 if(not f.fail())
842 {
843 return (val == 1);
844 }
845 return boost::none;
846#else
847 return boost::none;
848#endif
849 }
850
851 namespace
852 {
853 boost::mutex max_concurrency_lock;
854 unsigned max_concurrency = boost::thread::hardware_concurrency();
855 }
856
857 void set_max_concurrency(unsigned n)
858 {
859 if (n < 1)
860 n = boost::thread::hardware_concurrency();
861 unsigned hwc = boost::thread::hardware_concurrency();
862 if (n > hwc)
863 n = hwc;
864 boost::lock_guard<boost::mutex> lock(max_concurrency_lock);
865 max_concurrency = n;
866 }
867
869 {
870 boost::lock_guard<boost::mutex> lock(max_concurrency_lock);
871 return max_concurrency;
872 }
873
874 bool is_local_address(const std::string &address)
875 {
876 // always assume Tor/I2P addresses to be untrusted by default
877 if (boost::ends_with(address, ".onion") || boost::ends_with(address, ".i2p"))
878 {
879 MDEBUG("Address '" << address << "' is Tor/I2P, non local");
880 return false;
881 }
882
883 // extract host
886 {
887 MWARNING("Failed to determine whether address '" << address << "' is local, assuming not");
888 return false;
889 }
890 if (u_c.host.empty())
891 {
892 MWARNING("Failed to determine whether address '" << address << "' is local, assuming not");
893 return false;
894 }
895
896 // resolve to IP
897 boost::asio::io_service io_service;
898 boost::asio::ip::tcp::resolver resolver(io_service);
899 boost::asio::ip::tcp::resolver::query query(u_c.host, "");
900 boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query);
901 while (i != boost::asio::ip::tcp::resolver::iterator())
902 {
903 const boost::asio::ip::tcp::endpoint &ep = *i;
904 if (ep.address().is_loopback())
905 {
906 MDEBUG("Address '" << address << "' is local");
907 return true;
908 }
909 ++i;
910 }
911
912 MDEBUG("Address '" << address << "' is not local");
913 return false;
914 }
915 int vercmp(const char *v0, const char *v1)
916 {
917 std::vector<std::string> f0, f1;
918 boost::split(f0, v0, boost::is_any_of(".-"));
919 boost::split(f1, v1, boost::is_any_of(".-"));
920 for (size_t i = 0; i < std::max(f0.size(), f1.size()); ++i) {
921 if (i >= f0.size())
922 return -1;
923 if (i >= f1.size())
924 return 1;
925 int f0i = atoi(f0[i].c_str()), f1i = atoi(f1[i].c_str());
926 int n = f0i - f1i;
927 if (n)
928 return n;
929 }
930 return 0;
931 }
932
933 bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash)
934 {
935 SHA256_CTX ctx;
936 if (!SHA256_Init(&ctx))
937 return false;
938 if (!SHA256_Update(&ctx, data, len))
939 return false;
940 if (!SHA256_Final((unsigned char*)hash.data, &ctx))
941 return false;
942 return true;
943 }
944
945 bool sha256sum(const std::string &filename, crypto::hash &hash)
946 {
948 return false;
949 std::ifstream f;
950 f.exceptions(std::ifstream::failbit | std::ifstream::badbit);
951 f.open(filename, std::ios_base::binary | std::ios_base::in | std::ios::ate);
952 if (!f)
953 return false;
954 std::ifstream::pos_type file_size = f.tellg();
955 SHA256_CTX ctx;
956 if (!SHA256_Init(&ctx))
957 return false;
958 size_t size_left = file_size;
959 f.seekg(0, std::ios::beg);
960 while (size_left)
961 {
962 char buf[4096];
963 std::ifstream::pos_type read_size = size_left > sizeof(buf) ? sizeof(buf) : size_left;
964 f.read(buf, read_size);
965 if (!f || !f.good())
966 return false;
967 if (!SHA256_Update(&ctx, buf, read_size))
968 return false;
969 size_left -= read_size;
970 }
971 f.close();
972 if (!SHA256_Final((unsigned char*)hash.data, &ctx))
973 return false;
974 return true;
975 }
976
977 boost::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str)
978 {
979 auto pos = str.find(":");
980 bool r = pos != std::string::npos;
981 uint32_t major;
982 r = r && epee::string_tools::get_xtype_from_string(major, str.substr(0, pos));
983 uint32_t minor;
984 r = r && epee::string_tools::get_xtype_from_string(minor, str.substr(pos + 1));
985 if (r)
986 {
987 return std::make_pair(major, minor);
988 }
989 else
990 {
991 return {};
992 }
993 }
994
996 std::string s;
997 x++;
998 if (x == 1) {
999 s = "|";
1000 } else if (x == 2) {
1001 s = "/";
1002 } else if (x == 3) {
1003 s = "-";
1004 } else {
1005 s = "\\";
1006 x = 0;
1007 }
1008 std::cout << "\r" << s << std::flush;
1009 return x;
1010 }
1011
1012 std::string glob_to_regex(const std::string &val)
1013 {
1014 std::string newval;
1015
1016 bool escape = false;
1017 for (char c: val)
1018 {
1019 if (c == '*')
1020 newval += escape ? "*" : ".*";
1021 else if (c == '?')
1022 newval += escape ? "?" : ".";
1023 else if (c == '\\')
1024 newval += '\\', escape = !escape;
1025 else
1026 newval += c;
1027 }
1028 return newval;
1029 }
1030
1031#ifdef _WIN32
1032 std::string input_line_win()
1033 {
1034 HANDLE hConIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
1035 DWORD oldMode;
1036
1037 FlushConsoleInputBuffer(hConIn);
1038 GetConsoleMode(hConIn, &oldMode);
1039 SetConsoleMode(hConIn, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
1040
1041 wchar_t buffer[1024];
1042 DWORD read;
1043
1044 ReadConsoleW(hConIn, buffer, sizeof(buffer)/sizeof(wchar_t)-1, &read, nullptr);
1045 buffer[read] = 0;
1046
1047 SetConsoleMode(hConIn, oldMode);
1048 CloseHandle(hConIn);
1049
1050 int size_needed = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
1051 std::string buf(size_needed, '\0');
1052 WideCharToMultiByte(CP_UTF8, 0, buffer, -1, &buf[0], size_needed, NULL, NULL);
1053 buf.pop_back(); //size_needed includes null that we needed to have space for
1054 return buf;
1055 }
1056#endif
1057
1058 void closefrom(int fd)
1059 {
1060#if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ || defined __DragonFly__
1061 ::closefrom(fd);
1062#else
1063#if defined __GLIBC__
1064 const int sc_open_max = sysconf(_SC_OPEN_MAX);
1065 const int MAX_FDS = std::min(65536, sc_open_max);
1066#else
1067 const int MAX_FDS = 65536;
1068#endif
1069 while (fd < MAX_FDS)
1070 {
1071 close(fd);
1072 ++fd;
1073 }
1074#endif
1075 }
1076
1078 {
1079 char buffer[64];
1080 if (ts < 1234567890)
1081 return "<unknown>";
1082 time_t tt = ts;
1083 struct tm tm;
1085 strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
1086 return std::string(buffer);
1087 }
1088
1090 {
1091 // Use 1024 for "kilo", 1024*1024 for "mega" and so on instead of the more modern and standard-conforming
1092 // 1000, 1000*1000 and so on, to be consistent with other Electroneum code that also uses base 2 units
1093 struct byte_map
1094 {
1095 const char* const format;
1096 const std::uint64_t bytes;
1097 };
1098
1099 static constexpr const byte_map sizes[] =
1100 {
1101 {"%.0f B", 1024},
1102 {"%.2f KB", 1024 * 1024},
1103 {"%.2f MB", std::uint64_t(1024) * 1024 * 1024},
1104 {"%.2f GB", std::uint64_t(1024) * 1024 * 1024 * 1024},
1105 {"%.2f TB", std::uint64_t(1024) * 1024 * 1024 * 1024 * 1024}
1106 };
1107
1108 struct bytes_less
1109 {
1110 bool operator()(const byte_map& lhs, const byte_map& rhs) const noexcept
1111 {
1112 return lhs.bytes < rhs.bytes;
1113 }
1114 };
1115
1116 const auto size = std::upper_bound(
1117 std::begin(sizes), std::end(sizes) - 1, byte_map{"", bytes}, bytes_less{}
1118 );
1119 const std::uint64_t divisor = size->bytes / 1024;
1120 return (boost::format(size->format) % (double(bytes) / divisor)).str();
1121 }
1122
1123}
file_locker(const std::string &filename)
Definition util.cpp:238
bool locked() const
Definition util.cpp:296
const std::string & filename() const noexcept
Definition util.h:92
static private_file create(std::string filename)
Definition util.cpp:125
~private_file() noexcept
Deletes filename() and closes handle().
Definition util.cpp:228
private_file() noexcept
handle() == nullptr && filename.empty().
Definition util.cpp:120
std::FILE * handle() const noexcept
Definition util.h:91
#define CRYPTONOTE_NAME
const char * res
#define MERROR(x)
Definition misc_log_ex.h:73
void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size=MAX_LOG_FILE_SIZE, const std::size_t max_log_files=MAX_LOG_FILES)
Definition mlog.cpp:148
#define MWARNING(x)
Definition misc_log_ex.h:74
#define MDEBUG(x)
Definition misc_log_ex.h:76
#define MCLOG_RED(level, cat, x)
Definition misc_log_ex.h:58
#define LOG_ERROR(x)
Definition misc_log_ex.h:98
#define MINFO(x)
Definition misc_log_ex.h:75
#define LOG_PRINT_L2(x)
POD_CLASS hash
Definition hash.h:50
@ Warning
Useful when application has potentially harmful situtaions.
bool is_file_exist(const std::string &path)
bool get_gmt_time(time_t t, struct tm &tm)
bool parse_url(const std::string url_str, http::url_content &content)
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
Various Tools.
Definition tools.cpp:31
std::string get_human_readable_timestamp(uint64_t ts)
Definition util.cpp:1077
void closefrom(int fd)
Definition util.cpp:1058
void log_stack_trace(const char *msg)
int vercmp(const char *v0, const char *v1)
Definition util.cpp:915
std::string get_nix_version_display_string()
Definition util.cpp:554
bool disable_core_dumps()
Definition util.cpp:748
void set_max_concurrency(unsigned n)
Definition util.cpp:857
int display_simple_progress_spinner(int x)
Definition util.cpp:995
boost::optional< bool > is_hdd(const char *file_path)
Definition util.cpp:813
void set_strict_default_file_permissions(bool strict)
Definition util.cpp:803
std::error_code replace_file(const std::string &old_name, const std::string &new_name)
std::rename wrapper for nix and something strange for windows.
Definition util.cpp:648
bool sanitize_locale()
Definition util.cpp:690
std::string glob_to_regex(const std::string &val)
Definition util.cpp:1012
boost::optional< std::pair< uint32_t, uint32_t > > parse_subaddress_lookahead(const std::string &str)
Definition util.cpp:977
bool create_directories_if_necessary(const std::string &path)
creates directories for a path
Definition util.cpp:625
bool is_local_address(const std::string &address)
Definition util.cpp:874
ssize_t get_lockable_memory()
Definition util.cpp:763
bool on_startup()
Definition util.cpp:778
std::string get_human_readable_bytes(uint64_t bytes)
Definition util.cpp:1089
unsigned get_max_concurrency()
Definition util.cpp:868
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash)
Definition util.cpp:933
std::string get_os_version_string()
Returns the OS version string.
Definition util.cpp:566
std::string get_default_data_dir()
Returns the default data directory.
Definition util.cpp:600
const char * buf
unsigned int uint32_t
Definition stdint.h:126
unsigned char uint8_t
Definition stdint.h:124
_W64 signed int intptr_t
Definition stdint.h:164
unsigned __int64 uint64_t
Definition stdint.h:136
const char * address
Definition multisig.cpp:37
void ub_ctx_delete(struct ub_ctx *ctx)
int ub_ctx_async(struct ub_ctx *ctx, int dothread)
struct ub_ctx * ub_ctx_create(void)
int ub_ctx_zone_add(struct ub_ctx *ctx, const char *zone_name, const char *zone_type)