]>
Commit | Line | Data |
---|---|---|
2097c09a | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
f914f1a7 | 2 | // Copyright (c) 2009-2014 The Bitcoin Core developers |
c63a73d1 | 3 | // Distributed under the MIT software license, see the accompanying |
3a25a2b9 | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
36949554 | 5 | |
4c61ba40 WL |
6 | #if defined(HAVE_CONFIG_H) |
7 | #include "config/bitcoin-config.h" | |
8 | #endif | |
9 | ||
51ed9ec9 BD |
10 | #include "util.h" |
11 | ||
84ce18ca | 12 | #include "chainparamsbase.h" |
6354935c | 13 | #include "random.h" |
ad49c256 | 14 | #include "serialize.h" |
51ed9ec9 | 15 | #include "sync.h" |
ad49c256 WL |
16 | #include "utilstrencodings.h" |
17 | #include "utiltime.h" | |
51ed9ec9 | 18 | |
51ed9ec9 | 19 | #include <stdarg.h> |
51ed9ec9 | 20 | |
288fdc09 PW |
21 | #ifndef WIN32 |
22 | // for posix_fallocate | |
76c49c41 | 23 | #ifdef __linux__ |
51ed9ec9 BD |
24 | |
25 | #ifdef _POSIX_C_SOURCE | |
26 | #undef _POSIX_C_SOURCE | |
27 | #endif | |
28 | ||
288fdc09 | 29 | #define _POSIX_C_SOURCE 200112L |
51ed9ec9 | 30 | |
76c49c41 | 31 | #endif // __linux__ |
51ed9ec9 | 32 | |
b94595bb | 33 | #include <algorithm> |
288fdc09 | 34 | #include <fcntl.h> |
ba29a559 | 35 | #include <sys/resource.h> |
51ed9ec9 | 36 | #include <sys/stat.h> |
1f29d399 | 37 | |
51ed9ec9 | 38 | #else |
ed6d0b5f | 39 | |
ed6d0b5f PW |
40 | #ifdef _MSC_VER |
41 | #pragma warning(disable:4786) | |
42 | #pragma warning(disable:4804) | |
43 | #pragma warning(disable:4805) | |
44 | #pragma warning(disable:4717) | |
45 | #endif | |
51ed9ec9 | 46 | |
ed6d0b5f PW |
47 | #ifdef _WIN32_WINNT |
48 | #undef _WIN32_WINNT | |
49 | #endif | |
50 | #define _WIN32_WINNT 0x0501 | |
51ed9ec9 | 51 | |
ed6d0b5f PW |
52 | #ifdef _WIN32_IE |
53 | #undef _WIN32_IE | |
54 | #endif | |
234db30d | 55 | #define _WIN32_IE 0x0501 |
51ed9ec9 | 56 | |
ed6d0b5f PW |
57 | #define WIN32_LEAN_AND_MEAN 1 |
58 | #ifndef NOMINMAX | |
59 | #define NOMINMAX | |
60 | #endif | |
51ed9ec9 | 61 | |
5f986195 | 62 | #include <io.h> /* for _commit */ |
51ed9ec9 | 63 | #include <shlobj.h> |
ed6d0b5f | 64 | #endif |
2097c09a | 65 | |
4c61ba40 WL |
66 | #ifdef HAVE_SYS_PRCTL_H |
67 | #include <sys/prctl.h> | |
68 | #endif | |
69 | ||
51ed9ec9 BD |
70 | #include <boost/algorithm/string/case_conv.hpp> // for to_lower() |
71 | #include <boost/algorithm/string/join.hpp> | |
72 | #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith() | |
73 | #include <boost/filesystem.hpp> | |
74 | #include <boost/filesystem/fstream.hpp> | |
75 | #include <boost/foreach.hpp> | |
76 | #include <boost/program_options/detail/config_file.hpp> | |
77 | #include <boost/program_options/parsers.hpp> | |
ad49c256 | 78 | #include <boost/thread.hpp> |
51ed9ec9 BD |
79 | #include <openssl/crypto.h> |
80 | #include <openssl/rand.h> | |
81 | ||
82 | // Work around clang compilation problem in Boost 1.46: | |
83 | // /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup | |
84 | // See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options | |
85 | // http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION | |
86 | namespace boost { | |
e10dcf27 | 87 | |
51ed9ec9 BD |
88 | namespace program_options { |
89 | std::string to_internal(const std::string&); | |
90 | } | |
51ed9ec9 | 91 | |
e10dcf27 | 92 | } // namespace boost |
51ed9ec9 | 93 | |
2097c09a WL |
94 | using namespace std; |
95 | ||
96 | map<string, string> mapArgs; | |
97 | map<string, vector<string> > mapMultiArgs; | |
98 | bool fDebug = false; | |
99 | bool fPrintToConsole = false; | |
9e9056cd | 100 | bool fPrintToDebugLog = true; |
2097c09a WL |
101 | bool fDaemon = false; |
102 | bool fServer = false; | |
2097c09a | 103 | string strMiscWarning; |
2097c09a | 104 | bool fLogTimestamps = false; |
2e36866f | 105 | bool fLogIPs = false; |
ee337423 | 106 | volatile bool fReopenDebugLog = false; |
2097c09a | 107 | |
c63a73d1 | 108 | /** Init OpenSSL library multithreading support */ |
7f3ccb59 | 109 | static CCriticalSection** ppmutexOpenSSL; |
2097c09a WL |
110 | void locking_callback(int mode, int i, const char* file, int line) |
111 | { | |
7f3ccb59 PW |
112 | if (mode & CRYPTO_LOCK) { |
113 | ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]); | |
114 | } else { | |
115 | LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]); | |
116 | } | |
2097c09a WL |
117 | } |
118 | ||
119 | // Init | |
120 | class CInit | |
121 | { | |
122 | public: | |
123 | CInit() | |
124 | { | |
a7f82808 | 125 | // Init OpenSSL library multithreading support |
7f3ccb59 | 126 | ppmutexOpenSSL = (CCriticalSection**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(CCriticalSection*)); |
2097c09a | 127 | for (int i = 0; i < CRYPTO_num_locks(); i++) |
7f3ccb59 | 128 | ppmutexOpenSSL[i] = new CCriticalSection(); |
2097c09a WL |
129 | CRYPTO_set_locking_callback(locking_callback); |
130 | ||
6853e627 | 131 | #ifdef WIN32 |
cf04d836 | 132 | // Seed OpenSSL PRNG with current contents of the screen |
2097c09a WL |
133 | RAND_screen(); |
134 | #endif | |
135 | ||
cf04d836 | 136 | // Seed OpenSSL PRNG with performance counter |
2097c09a WL |
137 | RandAddSeed(); |
138 | } | |
139 | ~CInit() | |
140 | { | |
cf04d836 PK |
141 | // Securely erase the memory used by the PRNG |
142 | RAND_cleanup(); | |
a7f82808 | 143 | // Shutdown OpenSSL library multithreading support |
2097c09a WL |
144 | CRYPTO_set_locking_callback(NULL); |
145 | for (int i = 0; i < CRYPTO_num_locks(); i++) | |
146 | delete ppmutexOpenSSL[i]; | |
147 | OPENSSL_free(ppmutexOpenSSL); | |
148 | } | |
149 | } | |
150 | instance_of_cinit; | |
151 | ||
c63a73d1 MF |
152 | /** |
153 | * LogPrintf() has been broken a couple of times now | |
154 | * by well-meaning people adding mutexes in the most straightforward way. | |
155 | * It breaks because it may be called by global destructors during shutdown. | |
156 | * Since the order of destruction of static/global objects is undefined, | |
157 | * defining a mutex as a global object doesn't work (the mutex gets | |
158 | * destroyed, and then some later destructor calls OutputDebugStringF, | |
159 | * maybe indirectly, and you get a core dump at shutdown trying to lock | |
160 | * the mutex). | |
161 | */ | |
2097c09a | 162 | |
ee337423 | 163 | static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; |
c63a73d1 MF |
164 | /** |
165 | * We use boost::call_once() to make sure these are initialized | |
166 | * in a thread-safe manner the first time called: | |
167 | */ | |
ee337423 GA |
168 | static FILE* fileout = NULL; |
169 | static boost::mutex* mutexDebugLog = NULL; | |
170 | ||
171 | static void DebugPrintInit() | |
2097c09a | 172 | { |
ee337423 GA |
173 | assert(fileout == NULL); |
174 | assert(mutexDebugLog == NULL); | |
175 | ||
176 | boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; | |
177 | fileout = fopen(pathDebug.string().c_str(), "a"); | |
178 | if (fileout) setbuf(fileout, NULL); // unbuffered | |
179 | ||
180 | mutexDebugLog = new boost::mutex(); | |
181 | } | |
182 | ||
b77dfdc9 | 183 | bool LogAcceptCategory(const char* category) |
ee337423 | 184 | { |
e51321fb GA |
185 | if (category != NULL) |
186 | { | |
3b570559 | 187 | if (!fDebug) |
b77dfdc9 | 188 | return false; |
3b570559 | 189 | |
0b238b27 GA |
190 | // Give each thread quick access to -debug settings. |
191 | // This helps prevent issues debugging global destructors, | |
192 | // where mapMultiArgs might be deleted before another | |
193 | // global destructor calls LogPrint() | |
194 | static boost::thread_specific_ptr<set<string> > ptrCategory; | |
195 | if (ptrCategory.get() == NULL) | |
3b570559 | 196 | { |
0b238b27 GA |
197 | const vector<string>& categories = mapMultiArgs["-debug"]; |
198 | ptrCategory.reset(new set<string>(categories.begin(), categories.end())); | |
199 | // thread_specific_ptr automatically deletes the set when the thread ends. | |
3b570559 | 200 | } |
0b238b27 GA |
201 | const set<string>& setCategories = *ptrCategory.get(); |
202 | ||
203 | // if not debugging everything and not debugging specific category, LogPrint does nothing. | |
204 | if (setCategories.count(string("")) == 0 && | |
205 | setCategories.count(string(category)) == 0) | |
b77dfdc9 | 206 | return false; |
e51321fb | 207 | } |
b77dfdc9 WL |
208 | return true; |
209 | } | |
e51321fb | 210 | |
b77dfdc9 WL |
211 | int LogPrintStr(const std::string &str) |
212 | { | |
ee337423 | 213 | int ret = 0; // Returns total number of characters written |
2097c09a WL |
214 | if (fPrintToConsole) |
215 | { | |
216 | // print to console | |
b77dfdc9 | 217 | ret = fwrite(str.data(), 1, str.size(), stdout); |
e982b574 | 218 | fflush(stdout); |
2097c09a | 219 | } |
96ff9d64 | 220 | else if (fPrintToDebugLog && AreBaseParamsConfigured()) |
2097c09a | 221 | { |
ee337423 GA |
222 | static bool fStartedNewLine = true; |
223 | boost::call_once(&DebugPrintInit, debugPrintInitFlag); | |
2097c09a | 224 | |
ee337423 GA |
225 | if (fileout == NULL) |
226 | return ret; | |
227 | ||
228 | boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); | |
229 | ||
230 | // reopen the log file, if requested | |
231 | if (fReopenDebugLog) { | |
232 | fReopenDebugLog = false; | |
ee12c3d6 | 233 | boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; |
ee337423 GA |
234 | if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) |
235 | setbuf(fileout, NULL); // unbuffered | |
2097c09a | 236 | } |
2097c09a | 237 | |
ee337423 GA |
238 | // Debug print useful for profiling |
239 | if (fLogTimestamps && fStartedNewLine) | |
240 | ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); | |
b77dfdc9 | 241 | if (!str.empty() && str[str.size()-1] == '\n') |
ee337423 GA |
242 | fStartedNewLine = true; |
243 | else | |
244 | fStartedNewLine = false; | |
2097c09a | 245 | |
b77dfdc9 | 246 | ret = fwrite(str.data(), 1, str.size(), fileout); |
2097c09a WL |
247 | } |
248 | ||
2097c09a WL |
249 | return ret; |
250 | } | |
251 | ||
d64e124c CM |
252 | static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet) |
253 | { | |
254 | // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set | |
255 | if (name.find("-no") == 0) | |
256 | { | |
257 | std::string positive("-"); | |
258 | positive.append(name.begin()+3, name.end()); | |
259 | if (mapSettingsRet.count(positive) == 0) | |
260 | { | |
3260b4c0 | 261 | bool value = !GetBoolArg(name, false); |
d64e124c CM |
262 | mapSettingsRet[positive] = (value ? "1" : "0"); |
263 | } | |
264 | } | |
265 | } | |
266 | ||
3e468840 | 267 | void ParseParameters(int argc, const char* const argv[]) |
2097c09a WL |
268 | { |
269 | mapArgs.clear(); | |
270 | mapMultiArgs.clear(); | |
71aaff39 | 271 | |
2097c09a WL |
272 | for (int i = 1; i < argc; i++) |
273 | { | |
6032e4f4 WL |
274 | std::string str(argv[i]); |
275 | std::string strValue; | |
276 | size_t is_index = str.find('='); | |
277 | if (is_index != std::string::npos) | |
2097c09a | 278 | { |
6032e4f4 WL |
279 | strValue = str.substr(is_index+1); |
280 | str = str.substr(0, is_index); | |
2097c09a | 281 | } |
6032e4f4 WL |
282 | #ifdef WIN32 |
283 | boost::to_lower(str); | |
284 | if (boost::algorithm::starts_with(str, "/")) | |
285 | str = "-" + str.substr(1); | |
286 | #endif | |
71aaff39 | 287 | |
6032e4f4 | 288 | if (str[0] != '-') |
2097c09a | 289 | break; |
3ad9f8a7 | 290 | |
71aaff39 KZ |
291 | // Interpret --foo as -foo. |
292 | // If both --foo and -foo are set, the last takes effect. | |
293 | if (str.length() > 1 && str[1] == '-') | |
294 | str = str.substr(1); | |
295 | ||
6032e4f4 WL |
296 | mapArgs[str] = strValue; |
297 | mapMultiArgs[str].push_back(strValue); | |
2097c09a | 298 | } |
3ad9f8a7 GA |
299 | |
300 | // New 0.6 features: | |
301 | BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs) | |
302 | { | |
d64e124c | 303 | // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set |
71aaff39 | 304 | InterpretNegativeSetting(entry.first, mapArgs); |
3ad9f8a7 | 305 | } |
2097c09a WL |
306 | } |
307 | ||
3ae07355 GA |
308 | std::string GetArg(const std::string& strArg, const std::string& strDefault) |
309 | { | |
310 | if (mapArgs.count(strArg)) | |
311 | return mapArgs[strArg]; | |
312 | return strDefault; | |
313 | } | |
314 | ||
51ed9ec9 | 315 | int64_t GetArg(const std::string& strArg, int64_t nDefault) |
3ae07355 GA |
316 | { |
317 | if (mapArgs.count(strArg)) | |
318 | return atoi64(mapArgs[strArg]); | |
319 | return nDefault; | |
320 | } | |
321 | ||
322 | bool GetBoolArg(const std::string& strArg, bool fDefault) | |
323 | { | |
324 | if (mapArgs.count(strArg)) | |
325 | { | |
326 | if (mapArgs[strArg].empty()) | |
327 | return true; | |
328 | return (atoi(mapArgs[strArg]) != 0); | |
329 | } | |
330 | return fDefault; | |
331 | } | |
332 | ||
0fcf91ea GA |
333 | bool SoftSetArg(const std::string& strArg, const std::string& strValue) |
334 | { | |
335 | if (mapArgs.count(strArg)) | |
336 | return false; | |
337 | mapArgs[strArg] = strValue; | |
338 | return true; | |
339 | } | |
340 | ||
7bf8b7c2 | 341 | bool SoftSetBoolArg(const std::string& strArg, bool fValue) |
0fcf91ea GA |
342 | { |
343 | if (fValue) | |
344 | return SoftSetArg(strArg, std::string("1")); | |
345 | else | |
346 | return SoftSetArg(strArg, std::string("0")); | |
347 | } | |
348 | ||
1fdb9fa3 LV |
349 | static const int screenWidth = 79; |
350 | static const int optIndent = 2; | |
351 | static const int msgIndent = 7; | |
352 | ||
353 | std::string HelpMessageGroup(const std::string &message) { | |
354 | return std::string(message) + std::string("\n\n"); | |
355 | } | |
356 | ||
357 | std::string HelpMessageOpt(const std::string &option, const std::string &message) { | |
358 | return std::string(optIndent,' ') + std::string(option) + | |
359 | std::string("\n") + std::string(msgIndent,' ') + | |
360 | FormatParagraph(message, screenWidth - msgIndent, msgIndent) + | |
361 | std::string("\n\n"); | |
362 | } | |
363 | ||
27df4123 | 364 | static std::string FormatException(const std::exception* pex, const char* pszThread) |
2097c09a | 365 | { |
6853e627 | 366 | #ifdef WIN32 |
3e468840 | 367 | char pszModule[MAX_PATH] = ""; |
2097c09a WL |
368 | GetModuleFileNameA(NULL, pszModule, sizeof(pszModule)); |
369 | #else | |
370 | const char* pszModule = "bitcoin"; | |
371 | #endif | |
372 | if (pex) | |
29b79e4c | 373 | return strprintf( |
2097c09a WL |
374 | "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); |
375 | else | |
29b79e4c | 376 | return strprintf( |
2097c09a WL |
377 | "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); |
378 | } | |
379 | ||
27df4123 | 380 | void PrintExceptionContinue(const std::exception* pex, const char* pszThread) |
2097c09a | 381 | { |
29b79e4c | 382 | std::string message = FormatException(pex, pszThread); |
7d9d134b | 383 | LogPrintf("\n\n************************\n%s\n", message); |
29b79e4c WL |
384 | fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); |
385 | strMiscWarning = message; | |
2097c09a WL |
386 | } |
387 | ||
ee12c3d6 | 388 | boost::filesystem::path GetDefaultDataDir() |
2097c09a | 389 | { |
ee12c3d6 | 390 | namespace fs = boost::filesystem; |
3e468840 PK |
391 | // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin |
392 | // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin | |
2097c09a WL |
393 | // Mac: ~/Library/Application Support/Bitcoin |
394 | // Unix: ~/.bitcoin | |
6853e627 | 395 | #ifdef WIN32 |
2097c09a | 396 | // Windows |
3e468840 | 397 | return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin"; |
2097c09a | 398 | #else |
ee12c3d6 | 399 | fs::path pathRet; |
2097c09a WL |
400 | char* pszHome = getenv("HOME"); |
401 | if (pszHome == NULL || strlen(pszHome) == 0) | |
ee12c3d6 PW |
402 | pathRet = fs::path("/"); |
403 | else | |
404 | pathRet = fs::path(pszHome); | |
6853e627 | 405 | #ifdef MAC_OSX |
2097c09a | 406 | // Mac |
940e22fd | 407 | pathRet /= "Library/Application Support"; |
2b7709dc | 408 | TryCreateDirectory(pathRet); |
ee12c3d6 | 409 | return pathRet / "Bitcoin"; |
2097c09a WL |
410 | #else |
411 | // Unix | |
ee12c3d6 | 412 | return pathRet / ".bitcoin"; |
2097c09a WL |
413 | #endif |
414 | #endif | |
415 | } | |
416 | ||
ebdb9ff6 | 417 | static boost::filesystem::path pathCached; |
418 | static boost::filesystem::path pathCachedNetSpecific; | |
b94595bb GA |
419 | static CCriticalSection csPathCached; |
420 | ||
ee12c3d6 | 421 | const boost::filesystem::path &GetDataDir(bool fNetSpecific) |
2097c09a | 422 | { |
ee12c3d6 PW |
423 | namespace fs = boost::filesystem; |
424 | ||
b94595bb GA |
425 | LOCK(csPathCached); |
426 | ||
ebdb9ff6 | 427 | fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached; |
ee12c3d6 | 428 | |
faaeae1e | 429 | // This can be called during exceptions by LogPrintf(), so we cache the |
ee12c3d6 | 430 | // value so we don't have to do memory allocations after that. |
b94595bb | 431 | if (!path.empty()) |
ee12c3d6 PW |
432 | return path; |
433 | ||
ee12c3d6 | 434 | if (mapArgs.count("-datadir")) { |
f4203de3 PW |
435 | path = fs::system_complete(mapArgs["-datadir"]); |
436 | if (!fs::is_directory(path)) { | |
437 | path = ""; | |
438 | return path; | |
439 | } | |
ee12c3d6 PW |
440 | } else { |
441 | path = GetDefaultDataDir(); | |
2097c09a | 442 | } |
0e4b3175 | 443 | if (fNetSpecific) |
84ce18ca | 444 | path /= BaseParams().DataDir(); |
2097c09a | 445 | |
3e9c8bab | 446 | fs::create_directories(path); |
ee12c3d6 | 447 | |
ee12c3d6 | 448 | return path; |
2097c09a WL |
449 | } |
450 | ||
b94595bb GA |
451 | void ClearDatadirCache() |
452 | { | |
ebdb9ff6 | 453 | pathCached = boost::filesystem::path(); |
454 | pathCachedNetSpecific = boost::filesystem::path(); | |
b94595bb GA |
455 | } |
456 | ||
ee12c3d6 | 457 | boost::filesystem::path GetConfigFile() |
2097c09a | 458 | { |
3e468840 | 459 | boost::filesystem::path pathConfigFile(GetArg("-conf", "bitcoin.conf")); |
ac14bcc1 PK |
460 | if (!pathConfigFile.is_complete()) |
461 | pathConfigFile = GetDataDir(false) / pathConfigFile; | |
462 | ||
ee12c3d6 | 463 | return pathConfigFile; |
2097c09a WL |
464 | } |
465 | ||
f4203de3 | 466 | void ReadConfigFile(map<string, string>& mapSettingsRet, |
2097c09a WL |
467 | map<string, vector<string> >& mapMultiSettingsRet) |
468 | { | |
3e468840 | 469 | boost::filesystem::ifstream streamConfig(GetConfigFile()); |
2097c09a | 470 | if (!streamConfig.good()) |
f4203de3 | 471 | return; // No bitcoin.conf file is OK |
2097c09a WL |
472 | |
473 | set<string> setOptions; | |
474 | setOptions.insert("*"); | |
ee12c3d6 | 475 | |
3e468840 | 476 | for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) |
2097c09a WL |
477 | { |
478 | // Don't overwrite existing settings so command line settings override bitcoin.conf | |
479 | string strKey = string("-") + it->string_key; | |
480 | if (mapSettingsRet.count(strKey) == 0) | |
d64e124c | 481 | { |
2097c09a | 482 | mapSettingsRet[strKey] = it->value[0]; |
3e468840 | 483 | // interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set) |
d64e124c CM |
484 | InterpretNegativeSetting(strKey, mapSettingsRet); |
485 | } | |
2097c09a WL |
486 | mapMultiSettingsRet[strKey].push_back(it->value[0]); |
487 | } | |
b94595bb GA |
488 | // If datadir is changed in .conf file: |
489 | ClearDatadirCache(); | |
2097c09a WL |
490 | } |
491 | ||
d6712db3 | 492 | #ifndef WIN32 |
ee12c3d6 | 493 | boost::filesystem::path GetPidFile() |
2097c09a | 494 | { |
3e468840 | 495 | boost::filesystem::path pathPidFile(GetArg("-pid", "bitcoind.pid")); |
ee12c3d6 PW |
496 | if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile; |
497 | return pathPidFile; | |
2097c09a WL |
498 | } |
499 | ||
ee12c3d6 | 500 | void CreatePidFile(const boost::filesystem::path &path, pid_t pid) |
2097c09a | 501 | { |
ee12c3d6 | 502 | FILE* file = fopen(path.string().c_str(), "w"); |
f85c0974 | 503 | if (file) |
2097c09a WL |
504 | { |
505 | fprintf(file, "%d\n", pid); | |
506 | fclose(file); | |
507 | } | |
508 | } | |
a034c7eb | 509 | #endif |
2097c09a | 510 | |
768e5d52 JG |
511 | bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest) |
512 | { | |
513 | #ifdef WIN32 | |
5f986195 | 514 | return MoveFileExA(src.string().c_str(), dest.string().c_str(), |
8d657a65 | 515 | MOVEFILE_REPLACE_EXISTING) != 0; |
768e5d52 JG |
516 | #else |
517 | int rc = std::rename(src.string().c_str(), dest.string().c_str()); | |
518 | return (rc == 0); | |
519 | #endif /* WIN32 */ | |
520 | } | |
521 | ||
c63a73d1 MF |
522 | /** |
523 | * Ignores exceptions thrown by Boost's create_directory if the requested directory exists. | |
524 | * Specifically handles case where path p exists, but it wasn't possible for the user to | |
525 | * write to the parent directory. | |
526 | */ | |
2b7709dc BD |
527 | bool TryCreateDirectory(const boost::filesystem::path& p) |
528 | { | |
529 | try | |
530 | { | |
531 | return boost::filesystem::create_directory(p); | |
27df4123 | 532 | } catch (const boost::filesystem::filesystem_error&) { |
2b7709dc BD |
533 | if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p)) |
534 | throw; | |
535 | } | |
536 | ||
537 | // create_directory didn't create the directory, it had to have existed already | |
538 | return false; | |
539 | } | |
540 | ||
768e5d52 JG |
541 | void FileCommit(FILE *fileout) |
542 | { | |
4c0b2cde | 543 | fflush(fileout); // harmless if redundantly called |
768e5d52 | 544 | #ifdef WIN32 |
4c0b2cde PK |
545 | HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout)); |
546 | FlushFileBuffers(hFile); | |
768e5d52 | 547 | #else |
e9965213 PW |
548 | #if defined(__linux__) || defined(__NetBSD__) |
549 | fdatasync(fileno(fileout)); | |
e7bad10c GM |
550 | #elif defined(__APPLE__) && defined(F_FULLFSYNC) |
551 | fcntl(fileno(fileout), F_FULLFSYNC, 0); | |
e9965213 | 552 | #else |
768e5d52 | 553 | fsync(fileno(fileout)); |
e9965213 | 554 | #endif |
768e5d52 JG |
555 | #endif |
556 | } | |
557 | ||
1eb57879 PW |
558 | bool TruncateFile(FILE *file, unsigned int length) { |
559 | #if defined(WIN32) | |
560 | return _chsize(_fileno(file), length) == 0; | |
561 | #else | |
562 | return ftruncate(fileno(file), length) == 0; | |
563 | #endif | |
564 | } | |
565 | ||
c63a73d1 MF |
566 | /** |
567 | * this function tries to raise the file descriptor limit to the requested number. | |
568 | * It returns the actual file descriptor limit (which may be more or less than nMinFD) | |
569 | */ | |
ba29a559 PW |
570 | int RaiseFileDescriptorLimit(int nMinFD) { |
571 | #if defined(WIN32) | |
572 | return 2048; | |
573 | #else | |
574 | struct rlimit limitFD; | |
575 | if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) { | |
576 | if (limitFD.rlim_cur < (rlim_t)nMinFD) { | |
577 | limitFD.rlim_cur = nMinFD; | |
578 | if (limitFD.rlim_cur > limitFD.rlim_max) | |
579 | limitFD.rlim_cur = limitFD.rlim_max; | |
580 | setrlimit(RLIMIT_NOFILE, &limitFD); | |
581 | getrlimit(RLIMIT_NOFILE, &limitFD); | |
582 | } | |
583 | return limitFD.rlim_cur; | |
584 | } | |
585 | return nMinFD; // getrlimit failed, assume it's fine | |
586 | #endif | |
587 | } | |
588 | ||
c63a73d1 MF |
589 | /** |
590 | * this function tries to make a particular range of a file allocated (corresponding to disk space) | |
591 | * it is advisory, and the range specified in the arguments will never contain live data | |
592 | */ | |
bba89aa8 | 593 | void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { |
288fdc09 PW |
594 | #if defined(WIN32) |
595 | // Windows-specific version | |
596 | HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); | |
597 | LARGE_INTEGER nFileSize; | |
51ed9ec9 | 598 | int64_t nEndPos = (int64_t)offset + length; |
288fdc09 PW |
599 | nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF; |
600 | nFileSize.u.HighPart = nEndPos >> 32; | |
601 | SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN); | |
602 | SetEndOfFile(hFile); | |
603 | #elif defined(MAC_OSX) | |
604 | // OSX specific version | |
605 | fstore_t fst; | |
606 | fst.fst_flags = F_ALLOCATECONTIG; | |
607 | fst.fst_posmode = F_PEOFPOSMODE; | |
608 | fst.fst_offset = 0; | |
609 | fst.fst_length = (off_t)offset + length; | |
610 | fst.fst_bytesalloc = 0; | |
611 | if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) { | |
612 | fst.fst_flags = F_ALLOCATEALL; | |
613 | fcntl(fileno(file), F_PREALLOCATE, &fst); | |
614 | } | |
615 | ftruncate(fileno(file), fst.fst_length); | |
616 | #elif defined(__linux__) | |
617 | // Version using posix_fallocate | |
618 | off_t nEndPos = (off_t)offset + length; | |
619 | posix_fallocate(fileno(file), 0, nEndPos); | |
620 | #else | |
621 | // Fallback version | |
622 | // TODO: just write one byte per block | |
bba89aa8 PW |
623 | static const char buf[65536] = {}; |
624 | fseek(file, offset, SEEK_SET); | |
625 | while (length > 0) { | |
626 | unsigned int now = 65536; | |
627 | if (length < now) | |
628 | now = length; | |
629 | fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway | |
630 | length -= now; | |
631 | } | |
288fdc09 | 632 | #endif |
bba89aa8 PW |
633 | } |
634 | ||
2097c09a WL |
635 | void ShrinkDebugFile() |
636 | { | |
637 | // Scroll debug.log if it's getting too big | |
ee12c3d6 PW |
638 | boost::filesystem::path pathLog = GetDataDir() / "debug.log"; |
639 | FILE* file = fopen(pathLog.string().c_str(), "r"); | |
a486abd4 | 640 | if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000) |
2097c09a WL |
641 | { |
642 | // Restart the file with some of the end | |
fcb0a1bb | 643 | std::vector <char> vch(200000,0); |
1e735048 | 644 | fseek(file, -((long)vch.size()), SEEK_END); |
fcb0a1bb | 645 | int nBytes = fread(begin_ptr(vch), 1, vch.size(), file); |
2097c09a | 646 | fclose(file); |
f85c0974 | 647 | |
ee12c3d6 | 648 | file = fopen(pathLog.string().c_str(), "w"); |
f85c0974 | 649 | if (file) |
2097c09a | 650 | { |
fcb0a1bb | 651 | fwrite(begin_ptr(vch), 1, nBytes, file); |
2097c09a WL |
652 | fclose(file); |
653 | } | |
654 | } | |
3260b4c0 PK |
655 | else if (file != NULL) |
656 | fclose(file); | |
2097c09a WL |
657 | } |
658 | ||
ed6d0b5f | 659 | #ifdef WIN32 |
3e468840 PK |
660 | boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) |
661 | { | |
662 | namespace fs = boost::filesystem; | |
663 | ||
664 | char pszPath[MAX_PATH] = ""; | |
665 | ||
666 | if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate)) | |
667 | { | |
668 | return fs::path(pszPath); | |
669 | } | |
670 | ||
881a85a2 | 671 | LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n"); |
3e468840 PK |
672 | return fs::path(""); |
673 | } | |
ed6d0b5f | 674 | #endif |
429039d4 | 675 | |
597fa4cd PW |
676 | boost::filesystem::path GetTempPath() { |
677 | #if BOOST_FILESYSTEM_VERSION == 3 | |
678 | return boost::filesystem::temp_directory_path(); | |
679 | #else | |
680 | // TODO: remove when we don't support filesystem v2 anymore | |
681 | boost::filesystem::path path; | |
682 | #ifdef WIN32 | |
683 | char pszPath[MAX_PATH] = ""; | |
684 | ||
685 | if (GetTempPathA(MAX_PATH, pszPath)) | |
686 | path = boost::filesystem::path(pszPath); | |
687 | #else | |
688 | path = boost::filesystem::path("/tmp"); | |
689 | #endif | |
690 | if (path.empty() || !boost::filesystem::is_directory(path)) { | |
881a85a2 | 691 | LogPrintf("GetTempPath(): failed to find temp path\n"); |
597fa4cd PW |
692 | return boost::filesystem::path(""); |
693 | } | |
694 | return path; | |
695 | #endif | |
696 | } | |
697 | ||
429039d4 JG |
698 | void runCommand(std::string strCommand) |
699 | { | |
700 | int nErr = ::system(strCommand.c_str()); | |
701 | if (nErr) | |
7d9d134b | 702 | LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr); |
429039d4 JG |
703 | } |
704 | ||
96931d6f GS |
705 | void RenameThread(const char* name) |
706 | { | |
b277b0f1 | 707 | #if defined(PR_SET_NAME) |
96931d6f GS |
708 | // Only the first 15 characters are used (16 - NUL terminator) |
709 | ::prctl(PR_SET_NAME, name, 0, 0, 0); | |
304ca955 GS |
710 | #elif 0 && (defined(__FreeBSD__) || defined(__OpenBSD__)) |
711 | // TODO: This is currently disabled because it needs to be verified to work | |
712 | // on FreeBSD or OpenBSD first. When verified the '0 &&' part can be | |
713 | // removed. | |
714 | pthread_set_name_np(pthread_self(), name); | |
cd58f058 | 715 | |
850c570d | 716 | #elif defined(MAC_OSX) |
c8c2fbe0 | 717 | pthread_setname_np(name); |
96931d6f GS |
718 | #else |
719 | // Prevent warnings for unused parameters... | |
720 | (void)name; | |
721 | #endif | |
722 | } | |
0b47fe6b | 723 | |
5248ff40 SC |
724 | void SetupEnvironment() |
725 | { | |
ac14bcc1 | 726 | #ifndef WIN32 |
5248ff40 SC |
727 | try |
728 | { | |
ac14bcc1 | 729 | #if BOOST_FILESYSTEM_VERSION == 3 |
5248ff40 | 730 | boost::filesystem::path::codecvt(); // Raises runtime error if current locale is invalid |
ac14bcc1 | 731 | #else // boost filesystem v2 |
5248ff40 | 732 | std::locale(); // Raises runtime error if current locale is invalid |
ac14bcc1 | 733 | #endif |
27df4123 | 734 | } catch (const std::runtime_error&) { |
5248ff40 SC |
735 | setenv("LC_ALL", "C", 1); // Force C locale |
736 | } | |
ac14bcc1 | 737 | #endif |
5248ff40 | 738 | } |
3e8ac6af | 739 | |
610a8c07 WL |
740 | void SetThreadPriority(int nPriority) |
741 | { | |
742 | #ifdef WIN32 | |
743 | SetThreadPriority(GetCurrentThread(), nPriority); | |
744 | #else // WIN32 | |
745 | #ifdef PRIO_THREAD | |
746 | setpriority(PRIO_THREAD, 0, nPriority); | |
747 | #else // PRIO_THREAD | |
748 | setpriority(PRIO_PROCESS, 0, nPriority); | |
749 | #endif // PRIO_THREAD | |
750 | #endif // WIN32 | |
751 | } |