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