1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 /**
7 * Server/client environment: argument handling, config file parsing,
8 * thread wrappers, startup time
9 */
10 #ifndef BITCOIN_UTIL_SYSTEM_H
11 #define BITCOIN_UTIL_SYSTEM_H
12
13 #if defined(HAVE_CONFIG_H)
14 #include <config/bitcoin-config.h>
15 #endif
16
17 #include <attributes.h>
18 #include <compat.h>
19 #include <compat/assumptions.h>
20 #include <fs.h>
21 #include <logging.h>
22 #include <sync.h>
23 #include <tinyformat.h>
24 #include <util/memory.h>
25 #include <util/time.h>
26
27 #include <atomic>
28 #include <exception>
29 #include <map>
30 #include <set>
31 #include <stdint.h>
32 #include <string>
33 #include <unordered_set>
34 #include <utility>
35 #include <vector>
36
37 #include <boost/thread/condition_variable.hpp> // for boost::thread_interrupted
38
39 // Application startup time (used for uptime calculation)
40 int64_t GetStartupTime();
41
42 extern const char * const BITCOIN_CONF_FILENAME;
43
44 /** Translate a message to the native language of the user. */
45 const extern std::function<std::string(const char*)> G_TRANSLATION_FUN;
46
47 /**
48 * Translation function.
49 * If no translation function is set, simply return the input.
50 */
_(const char * psz)51 inline std::string _(const char* psz)
52 {
53 return G_TRANSLATION_FUN ? (G_TRANSLATION_FUN)(psz) : psz;
54 }
55
56 void SetupEnvironment();
57 bool SetupNetworking();
58
59 template<typename... Args>
error(const char * fmt,const Args &...args)60 bool error(const char* fmt, const Args&... args)
61 {
62 LogPrintf("ERROR: %s\n", tfm::format(fmt, args...));
63 return false;
64 }
65
66 void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
67 bool FileCommit(FILE *file);
68 bool TruncateFile(FILE *file, unsigned int length);
69 int RaiseFileDescriptorLimit(int nMinFD);
70 void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
71 bool RenameOver(fs::path src, fs::path dest);
72 bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false);
73 void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name);
74 bool DirIsWritable(const fs::path& directory);
75
76 /** Release all directory locks. This is used for unit testing only, at runtime
77 * the global destructor will take care of the locks.
78 */
79 void ReleaseDirectoryLocks();
80
81 bool TryCreateDirectories(const fs::path& p);
82 fs::path GetDefaultDataDir();
83 // The blocks directory is always net specific.
84 const fs::path &GetBlocksDir();
85 const fs::path &GetDataDir(bool fNetSpecific = true);
86 void ClearDatadirCache();
87 fs::path GetConfigFile(const std::string& confPath);
88 #ifdef WIN32
89 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
90 #endif
91 void runCommand(const std::string& strCommand);
92
93 /**
94 * Most paths passed as configuration arguments are treated as relative to
95 * the datadir if they are not absolute.
96 *
97 * @param path The path to be conditionally prefixed with datadir.
98 * @param net_specific Forwarded to GetDataDir().
99 * @return The normalized path.
100 */
101 fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific = true);
102
IsSwitchChar(char c)103 inline bool IsSwitchChar(char c)
104 {
105 #ifdef WIN32
106 return c == '-' || c == '/';
107 #else
108 return c == '-';
109 #endif
110 }
111
112 enum class OptionsCategory {
113 OPTIONS,
114 CONNECTION,
115 WALLET,
116 WALLET_DEBUG_TEST,
117 ZMQ,
118 DEBUG_TEST,
119 CHAINPARAMS,
120 NODE_RELAY,
121 BLOCK_CREATION,
122 RPC,
123 GUI,
124 COMMANDS,
125 REGISTER_COMMANDS,
126
127 HIDDEN // Always the last option to avoid printing these in the help
128 };
129
130 class ArgsManager
131 {
132 protected:
133 friend class ArgsManagerHelper;
134
135 struct Arg
136 {
137 std::string m_help_param;
138 std::string m_help_text;
139 bool m_debug_only;
140
ArgArg141 Arg(const std::string& help_param, const std::string& help_text, bool debug_only) : m_help_param(help_param), m_help_text(help_text), m_debug_only(debug_only) {};
142 };
143
144 mutable CCriticalSection cs_args;
145 std::map<std::string, std::vector<std::string>> m_override_args GUARDED_BY(cs_args);
146 std::map<std::string, std::vector<std::string>> m_config_args GUARDED_BY(cs_args);
147 std::string m_network GUARDED_BY(cs_args);
148 std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
149 std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
150 std::set<std::string> m_config_sections GUARDED_BY(cs_args);
151
152 NODISCARD bool ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys = false);
153
154 public:
155 ArgsManager();
156
157 /**
158 * Select the network in use
159 */
160 void SelectConfigNetwork(const std::string& network);
161
162 NODISCARD bool ParseParameters(int argc, const char* const argv[], std::string& error);
163 NODISCARD bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
164
165 /**
166 * Log warnings for options in m_section_only_args when
167 * they are specified in the default section but not overridden
168 * on the command line or in a network-specific section in the
169 * config file.
170 */
171 const std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
172
173 /**
174 * Log warnings for unrecognized section names in the config file.
175 */
176 const std::set<std::string> GetUnrecognizedSections() const;
177
178 /**
179 * Return a vector of strings of the given argument
180 *
181 * @param strArg Argument to get (e.g. "-foo")
182 * @return command-line arguments
183 */
184 std::vector<std::string> GetArgs(const std::string& strArg) const;
185
186 /**
187 * Return true if the given argument has been manually set
188 *
189 * @param strArg Argument to get (e.g. "-foo")
190 * @return true if the argument has been set
191 */
192 bool IsArgSet(const std::string& strArg) const;
193
194 /**
195 * Return true if the argument was originally passed as a negated option,
196 * i.e. -nofoo.
197 *
198 * @param strArg Argument to get (e.g. "-foo")
199 * @return true if the argument was passed negated
200 */
201 bool IsArgNegated(const std::string& strArg) const;
202
203 /**
204 * Return string argument or default value
205 *
206 * @param strArg Argument to get (e.g. "-foo")
207 * @param strDefault (e.g. "1")
208 * @return command-line argument or default value
209 */
210 std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
211
212 /**
213 * Return integer argument or default value
214 *
215 * @param strArg Argument to get (e.g. "-foo")
216 * @param nDefault (e.g. 1)
217 * @return command-line argument (0 if invalid number) or default value
218 */
219 int64_t GetArg(const std::string& strArg, int64_t nDefault) const;
220
221 /**
222 * Return boolean argument or default value
223 *
224 * @param strArg Argument to get (e.g. "-foo")
225 * @param fDefault (true or false)
226 * @return command-line argument or default value
227 */
228 bool GetBoolArg(const std::string& strArg, bool fDefault) const;
229
230 /**
231 * Set an argument if it doesn't already have a value
232 *
233 * @param strArg Argument to set (e.g. "-foo")
234 * @param strValue Value (e.g. "1")
235 * @return true if argument gets set, false if it already had a value
236 */
237 bool SoftSetArg(const std::string& strArg, const std::string& strValue);
238
239 /**
240 * Set a boolean argument if it doesn't already have a value
241 *
242 * @param strArg Argument to set (e.g. "-foo")
243 * @param fValue Value (e.g. false)
244 * @return true if argument gets set, false if it already had a value
245 */
246 bool SoftSetBoolArg(const std::string& strArg, bool fValue);
247
248 // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
249 // been set. Also called directly in testing.
250 void ForceSetArg(const std::string& strArg, const std::string& strValue);
251
252 /**
253 * Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
254 * @return CBaseChainParams::MAIN by default; raises runtime error if an invalid combination is given.
255 */
256 std::string GetChainName() const;
257
258 /**
259 * Add argument
260 */
261 void AddArg(const std::string& name, const std::string& help, const bool debug_only, const OptionsCategory& cat);
262
263 /**
264 * Add many hidden arguments
265 */
266 void AddHiddenArgs(const std::vector<std::string>& args);
267
268 /**
269 * Clear available arguments
270 */
ClearArgs()271 void ClearArgs() {
272 LOCK(cs_args);
273 m_available_args.clear();
274 }
275
276 /**
277 * Get the help string
278 */
279 std::string GetHelpMessage() const;
280
281 /**
282 * Check whether we know of this arg
283 */
284 bool IsArgKnown(const std::string& key) const;
285 };
286
287 extern ArgsManager gArgs;
288
289 /**
290 * @return true if help has been requested via a command-line arg
291 */
292 bool HelpRequested(const ArgsManager& args);
293
294 /** Add help options to the args manager */
295 void SetupHelpOptions(ArgsManager& args);
296
297 /**
298 * Format a string to be used as group of options in help messages
299 *
300 * @param message Group name (e.g. "RPC server options:")
301 * @return the formatted string
302 */
303 std::string HelpMessageGroup(const std::string& message);
304
305 /**
306 * Format a string to be used as option description in help messages
307 *
308 * @param option Option message (e.g. "-rpcuser=<user>")
309 * @param message Option description (e.g. "Username for JSON-RPC connections")
310 * @return the formatted string
311 */
312 std::string HelpMessageOpt(const std::string& option, const std::string& message);
313
314 /**
315 * Return the number of cores available on the current system.
316 * @note This does count virtual cores, such as those provided by HyperThreading.
317 */
318 int GetNumCores();
319
320 void RenameThread(const char* name);
321
322 /**
323 * .. and a wrapper that just calls func once
324 */
TraceThread(const char * name,Callable func)325 template <typename Callable> void TraceThread(const char* name, Callable func)
326 {
327 std::string s = strprintf("litecoin-%s", name);
328 RenameThread(s.c_str());
329 try
330 {
331 LogPrintf("%s thread start\n", name);
332 func();
333 LogPrintf("%s thread exit\n", name);
334 }
335 catch (const boost::thread_interrupted&)
336 {
337 LogPrintf("%s thread interrupt\n", name);
338 throw;
339 }
340 catch (const std::exception& e) {
341 PrintExceptionContinue(&e, name);
342 throw;
343 }
344 catch (...) {
345 PrintExceptionContinue(nullptr, name);
346 throw;
347 }
348 }
349
350 std::string CopyrightHolders(const std::string& strPrefix);
351
352 /**
353 * On platforms that support it, tell the kernel the calling thread is
354 * CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details.
355 *
356 * @return The return value of sched_setschedule(), or 1 on systems without
357 * sched_setschedule().
358 */
359 int ScheduleBatchPriority();
360
361 namespace util {
362
363 //! Simplification of std insertion
364 template <typename Tdst, typename Tsrc>
insert(Tdst & dst,const Tsrc & src)365 inline void insert(Tdst& dst, const Tsrc& src) {
366 dst.insert(dst.begin(), src.begin(), src.end());
367 }
368 template <typename TsetT, typename Tsrc>
insert(std::set<TsetT> & dst,const Tsrc & src)369 inline void insert(std::set<TsetT>& dst, const Tsrc& src) {
370 dst.insert(src.begin(), src.end());
371 }
372
373 #ifdef WIN32
374 class WinCmdLineArgs
375 {
376 public:
377 WinCmdLineArgs();
378 ~WinCmdLineArgs();
379 std::pair<int, char**> get();
380
381 private:
382 int argc;
383 char** argv;
384 std::vector<std::string> args;
385 };
386 #endif
387
388 } // namespace util
389
390 #endif // BITCOIN_UTIL_SYSTEM_H
391