1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2020 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/settings.h>
25 #include <util/time.h>
26
27 #include <any>
28 #include <exception>
29 #include <map>
30 #include <optional>
31 #include <set>
32 #include <stdint.h>
33 #include <string>
34 #include <utility>
35 #include <vector>
36
37 class UniValue;
38
39 // Application startup time (used for uptime calculation)
40 int64_t GetStartupTime();
41
42 extern const char * const BITCOIN_CONF_FILENAME;
43 extern const char * const BITCOIN_SETTINGS_FILENAME;
44
45 void SetupEnvironment();
46 bool SetupNetworking();
47
48 template<typename... Args>
error(const char * fmt,const Args &...args)49 bool error(const char* fmt, const Args&... args)
50 {
51 LogPrintf("ERROR: %s\n", tfm::format(fmt, args...));
52 return false;
53 }
54
55 void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
56
57 /**
58 * Ensure file contents are fully committed to disk, using a platform-specific
59 * feature analogous to fsync().
60 */
61 bool FileCommit(FILE *file);
62
63 /**
64 * Sync directory contents. This is required on some environments to ensure that
65 * newly created files are committed to disk.
66 */
67 void DirectoryCommit(const fs::path &dirname);
68
69 bool TruncateFile(FILE *file, unsigned int length);
70 int RaiseFileDescriptorLimit(int nMinFD);
71 void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
72 [[nodiscard]] bool RenameOver(fs::path src, fs::path dest);
73 bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false);
74 void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name);
75 bool DirIsWritable(const fs::path& directory);
76 bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes = 0);
77
78 /** Get the size of a file by scanning it.
79 *
80 * @param[in] path The file path
81 * @param[in] max Stop seeking beyond this limit
82 * @return The file size or max
83 */
84 std::streampos GetFileSize(const char* path, std::streamsize max = std::numeric_limits<std::streamsize>::max());
85
86 /** Release all directory locks. This is used for unit testing only, at runtime
87 * the global destructor will take care of the locks.
88 */
89 void ReleaseDirectoryLocks();
90
91 bool TryCreateDirectories(const fs::path& p);
92 fs::path GetDefaultDataDir();
93 // Return true if -datadir option points to a valid directory or is not specified.
94 bool CheckDataDirOption();
95 fs::path GetConfigFile(const std::string& confPath);
96 #ifdef WIN32
97 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
98 #endif
99 #ifndef WIN32
100 std::string ShellEscape(const std::string& arg);
101 #endif
102 #if HAVE_SYSTEM
103 void runCommand(const std::string& strCommand);
104 #endif
105 /**
106 * Execute a command which returns JSON, and parse the result.
107 *
108 * @param str_command The command to execute, including any arguments
109 * @param str_std_in string to pass to stdin
110 * @return parsed JSON
111 */
112 UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in="");
113
114 /**
115 * Most paths passed as configuration arguments are treated as relative to
116 * the datadir if they are not absolute.
117 *
118 * @param path The path to be conditionally prefixed with datadir.
119 * @param net_specific Use network specific datadir variant
120 * @return The normalized path.
121 */
122 fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific = true);
123
IsSwitchChar(char c)124 inline bool IsSwitchChar(char c)
125 {
126 #ifdef WIN32
127 return c == '-' || c == '/';
128 #else
129 return c == '-';
130 #endif
131 }
132
133 enum class OptionsCategory {
134 OPTIONS,
135 CONNECTION,
136 WALLET,
137 WALLET_DEBUG_TEST,
138 ZMQ,
139 DEBUG_TEST,
140 CHAINPARAMS,
141 NODE_RELAY,
142 BLOCK_CREATION,
143 RPC,
144 GUI,
145 COMMANDS,
146 REGISTER_COMMANDS,
147
148 HIDDEN // Always the last option to avoid printing these in the help
149 };
150
151 struct SectionInfo
152 {
153 std::string m_name;
154 std::string m_file;
155 int m_line;
156 };
157
158 class ArgsManager
159 {
160 public:
161 enum Flags : uint32_t {
162 // Boolean options can accept negation syntax -noOPTION or -noOPTION=1
163 ALLOW_BOOL = 0x01,
164 ALLOW_INT = 0x02,
165 ALLOW_STRING = 0x04,
166 ALLOW_ANY = ALLOW_BOOL | ALLOW_INT | ALLOW_STRING,
167 DEBUG_ONLY = 0x100,
168 /* Some options would cause cross-contamination if values for
169 * mainnet were used while running on regtest/testnet (or vice-versa).
170 * Setting them as NETWORK_ONLY ensures that sharing a config file
171 * between mainnet and regtest/testnet won't cause problems due to these
172 * parameters by accident. */
173 NETWORK_ONLY = 0x200,
174 // This argument's value is sensitive (such as a password).
175 SENSITIVE = 0x400,
176 COMMAND = 0x800,
177 };
178
179 protected:
180 struct Arg
181 {
182 std::string m_help_param;
183 std::string m_help_text;
184 unsigned int m_flags;
185 };
186
187 mutable RecursiveMutex cs_args;
188 util::Settings m_settings GUARDED_BY(cs_args);
189 std::vector<std::string> m_command GUARDED_BY(cs_args);
190 std::string m_network GUARDED_BY(cs_args);
191 std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
192 std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
GUARDED_BY(cs_args)193 bool m_accept_any_command GUARDED_BY(cs_args){true};
194 std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
195 mutable fs::path m_cached_blocks_path GUARDED_BY(cs_args);
196 mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
197 mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
198
199 [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);
200
201 /**
202 * Returns true if settings values from the default section should be used,
203 * depending on the current network and whether the setting is
204 * network-specific.
205 */
206 bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args);
207
208 /**
209 * Get setting value.
210 *
211 * Result will be null if setting was unset, true if "-setting" argument was passed
212 * false if "-nosetting" argument was passed, and a string if a "-setting=value"
213 * argument was passed.
214 */
215 util::SettingsValue GetSetting(const std::string& arg) const;
216
217 /**
218 * Get list of setting values.
219 */
220 std::vector<util::SettingsValue> GetSettingsList(const std::string& arg) const;
221
222 public:
223 ArgsManager();
224 ~ArgsManager();
225
226 /**
227 * Select the network in use
228 */
229 void SelectConfigNetwork(const std::string& network);
230
231 [[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error);
232 [[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
233
234 /**
235 * Log warnings for options in m_section_only_args when
236 * they are specified in the default section but not overridden
237 * on the command line or in a network-specific section in the
238 * config file.
239 */
240 const std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
241
242 /**
243 * Log warnings for unrecognized section names in the config file.
244 */
245 const std::list<SectionInfo> GetUnrecognizedSections() const;
246
247 struct Command {
248 /** The command (if one has been registered with AddCommand), or empty */
249 std::string command;
250 /**
251 * If command is non-empty: Any args that followed it
252 * If command is empty: The unregistered command and any args that followed it
253 */
254 std::vector<std::string> args;
255 };
256 /**
257 * Get the command and command args (returns std::nullopt if no command provided)
258 */
259 std::optional<const Command> GetCommand() const;
260
261 /**
262 * Get blocks directory path
263 *
264 * @return Blocks path which is network specific
265 */
266 const fs::path& GetBlocksDirPath() const;
267
268 /**
269 * Get data directory path
270 *
271 * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
272 * @post Returned directory path is created unless it is empty
273 */
GetDataDirBase()274 const fs::path& GetDataDirBase() const { return GetDataDir(false); }
275
276 /**
277 * Get data directory path with appended network identifier
278 *
279 * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
280 * @post Returned directory path is created unless it is empty
281 */
GetDataDirNet()282 const fs::path& GetDataDirNet() const { return GetDataDir(true); }
283
284 /**
285 * Clear cached directory paths
286 */
287 void ClearPathCache();
288
289 /**
290 * Return a vector of strings of the given argument
291 *
292 * @param strArg Argument to get (e.g. "-foo")
293 * @return command-line arguments
294 */
295 std::vector<std::string> GetArgs(const std::string& strArg) const;
296
297 /**
298 * Return true if the given argument has been manually set
299 *
300 * @param strArg Argument to get (e.g. "-foo")
301 * @return true if the argument has been set
302 */
303 bool IsArgSet(const std::string& strArg) const;
304
305 /**
306 * Return true if the argument was originally passed as a negated option,
307 * i.e. -nofoo.
308 *
309 * @param strArg Argument to get (e.g. "-foo")
310 * @return true if the argument was passed negated
311 */
312 bool IsArgNegated(const std::string& strArg) const;
313
314 /**
315 * Return string argument or default value
316 *
317 * @param strArg Argument to get (e.g. "-foo")
318 * @param strDefault (e.g. "1")
319 * @return command-line argument or default value
320 */
321 std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
322
323 /**
324 * Return integer argument or default value
325 *
326 * @param strArg Argument to get (e.g. "-foo")
327 * @param nDefault (e.g. 1)
328 * @return command-line argument (0 if invalid number) or default value
329 */
330 int64_t GetArg(const std::string& strArg, int64_t nDefault) const;
331
332 /**
333 * Return boolean argument or default value
334 *
335 * @param strArg Argument to get (e.g. "-foo")
336 * @param fDefault (true or false)
337 * @return command-line argument or default value
338 */
339 bool GetBoolArg(const std::string& strArg, bool fDefault) const;
340
341 /**
342 * Set an argument if it doesn't already have a value
343 *
344 * @param strArg Argument to set (e.g. "-foo")
345 * @param strValue Value (e.g. "1")
346 * @return true if argument gets set, false if it already had a value
347 */
348 bool SoftSetArg(const std::string& strArg, const std::string& strValue);
349
350 /**
351 * Set a boolean argument if it doesn't already have a value
352 *
353 * @param strArg Argument to set (e.g. "-foo")
354 * @param fValue Value (e.g. false)
355 * @return true if argument gets set, false if it already had a value
356 */
357 bool SoftSetBoolArg(const std::string& strArg, bool fValue);
358
359 // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
360 // been set. Also called directly in testing.
361 void ForceSetArg(const std::string& strArg, const std::string& strValue);
362
363 /**
364 * Returns the appropriate chain name from the program arguments.
365 * @return CBaseChainParams::MAIN by default; raises runtime error if an invalid combination is given.
366 */
367 std::string GetChainName() const;
368
369 /**
370 * Add argument
371 */
372 void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat);
373
374 /**
375 * Add subcommand
376 */
377 void AddCommand(const std::string& cmd, const std::string& help);
378
379 /**
380 * Add many hidden arguments
381 */
382 void AddHiddenArgs(const std::vector<std::string>& args);
383
384 /**
385 * Clear available arguments
386 */
ClearArgs()387 void ClearArgs() {
388 LOCK(cs_args);
389 m_available_args.clear();
390 m_network_only_args.clear();
391 }
392
393 /**
394 * Get the help string
395 */
396 std::string GetHelpMessage() const;
397
398 /**
399 * Return Flags for known arg.
400 * Return nullopt for unknown arg.
401 */
402 std::optional<unsigned int> GetArgFlags(const std::string& name) const;
403
404 /**
405 * Read and update settings file with saved settings. This needs to be
406 * called after SelectParams() because the settings file location is
407 * network-specific.
408 */
409 bool InitSettings(std::string& error);
410
411 /**
412 * Get settings file path, or return false if read-write settings were
413 * disabled with -nosettings.
414 */
415 bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false) const;
416
417 /**
418 * Read settings file. Push errors to vector, or log them if null.
419 */
420 bool ReadSettingsFile(std::vector<std::string>* errors = nullptr);
421
422 /**
423 * Write settings file. Push errors to vector, or log them if null.
424 */
425 bool WriteSettingsFile(std::vector<std::string>* errors = nullptr) const;
426
427 /**
428 * Access settings with lock held.
429 */
430 template <typename Fn>
LockSettings(Fn && fn)431 void LockSettings(Fn&& fn)
432 {
433 LOCK(cs_args);
434 fn(m_settings);
435 }
436
437 /**
438 * Log the config file options and the command line arguments,
439 * useful for troubleshooting.
440 */
441 void LogArgs() const;
442
443 private:
444 /**
445 * Get data directory path
446 *
447 * @param net_specific Append network identifier to the returned path
448 * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
449 * @post Returned directory path is created unless it is empty
450 */
451 const fs::path& GetDataDir(bool net_specific) const;
452
453 // Helper function for LogArgs().
454 void logArgsPrefix(
455 const std::string& prefix,
456 const std::string& section,
457 const std::map<std::string, std::vector<util::SettingsValue>>& args) const;
458 };
459
460 extern ArgsManager gArgs;
461
462 /**
463 * @return true if help has been requested via a command-line arg
464 */
465 bool HelpRequested(const ArgsManager& args);
466
467 /** Add help options to the args manager */
468 void SetupHelpOptions(ArgsManager& args);
469
470 /**
471 * Format a string to be used as group of options in help messages
472 *
473 * @param message Group name (e.g. "RPC server options:")
474 * @return the formatted string
475 */
476 std::string HelpMessageGroup(const std::string& message);
477
478 /**
479 * Format a string to be used as option description in help messages
480 *
481 * @param option Option message (e.g. "-rpcuser=<user>")
482 * @param message Option description (e.g. "Username for JSON-RPC connections")
483 * @return the formatted string
484 */
485 std::string HelpMessageOpt(const std::string& option, const std::string& message);
486
487 /**
488 * Return the number of cores available on the current system.
489 * @note This does count virtual cores, such as those provided by HyperThreading.
490 */
491 int GetNumCores();
492
493 std::string CopyrightHolders(const std::string& strPrefix);
494
495 /**
496 * On platforms that support it, tell the kernel the calling thread is
497 * CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details.
498 *
499 */
500 void ScheduleBatchPriority();
501
502 namespace util {
503
504 //! Simplification of std insertion
505 template <typename Tdst, typename Tsrc>
insert(Tdst & dst,const Tsrc & src)506 inline void insert(Tdst& dst, const Tsrc& src) {
507 dst.insert(dst.begin(), src.begin(), src.end());
508 }
509 template <typename TsetT, typename Tsrc>
insert(std::set<TsetT> & dst,const Tsrc & src)510 inline void insert(std::set<TsetT>& dst, const Tsrc& src) {
511 dst.insert(src.begin(), src.end());
512 }
513
514 /**
515 * Helper function to access the contained object of a std::any instance.
516 * Returns a pointer to the object if passed instance has a value and the type
517 * matches, nullptr otherwise.
518 */
519 template<typename T>
AnyPtr(const std::any & any)520 T* AnyPtr(const std::any& any) noexcept
521 {
522 T* const* ptr = std::any_cast<T*>(&any);
523 return ptr ? *ptr : nullptr;
524 }
525
526 #ifdef WIN32
527 class WinCmdLineArgs
528 {
529 public:
530 WinCmdLineArgs();
531 ~WinCmdLineArgs();
532 std::pair<int, char**> get();
533
534 private:
535 int argc;
536 char** argv;
537 std::vector<std::string> args;
538 };
539 #endif
540
541 } // namespace util
542
543 #endif // BITCOIN_UTIL_SYSTEM_H
544