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