fix -datadir=./subdir relative path,
[novacoin.git] / init.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "headers.h"
6
7
8
9
10
11
12
13
14 //////////////////////////////////////////////////////////////////////////////
15 //
16 // Shutdown
17 //
18
19 void ExitTimeout(void* parg)
20 {
21 #ifdef __WXMSW__
22     Sleep(5000);
23     ExitProcess(0);
24 #endif
25 }
26
27 void Shutdown(void* parg)
28 {
29     static CCriticalSection cs_Shutdown;
30     static bool fTaken;
31     bool fFirstThread;
32     CRITICAL_BLOCK(cs_Shutdown)
33     {
34         fFirstThread = !fTaken;
35         fTaken = true;
36     }
37     static bool fExit;
38     if (fFirstThread)
39     {
40         fShutdown = true;
41         nTransactionsUpdated++;
42         DBFlush(false);
43         StopNode();
44         DBFlush(true);
45         CreateThread(ExitTimeout, NULL);
46         Sleep(50);
47         printf("Bitcoin exiting\n\n");
48         fExit = true;
49         exit(0);
50     }
51     else
52     {
53         while (!fExit)
54             Sleep(500);
55         Sleep(100);
56         ExitThread(0);
57     }
58 }
59
60
61
62
63
64
65 //////////////////////////////////////////////////////////////////////////////
66 //
67 // Start
68 //
69
70 #ifndef GUI
71 int main(int argc, char* argv[])
72 {
73     for (int i = 1; i < argc; i++)
74         if (!IsSwitchChar(argv[i][0]))
75             fCommandLine = true;
76     fDaemon = !fCommandLine;
77
78 #ifdef __WXGTK__
79     if (!fCommandLine)
80     {
81         // Daemonize
82         pid_t pid = fork();
83         if (pid < 0)
84         {
85             fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
86             return 1;
87         }
88         if (pid > 0)
89             pthread_exit((void*)0);
90     }
91 #endif
92
93     if (!AppInit(argc, argv))
94         return 1;
95
96     while (!fShutdown)
97         Sleep(1000000);
98     return 0;
99 }
100 #endif
101
102 bool AppInit(int argc, char* argv[])
103 {
104     bool fRet = false;
105     try
106     {
107         fRet = AppInit2(argc, argv);
108     }
109     catch (std::exception& e) {
110         PrintException(&e, "AppInit()");
111     } catch (...) {
112         PrintException(NULL, "AppInit()");
113     }
114     if (!fRet)
115         Shutdown(NULL);
116     return fRet;
117 }
118
119 bool AppInit2(int argc, char* argv[])
120 {
121 #ifdef _MSC_VER
122     // Turn off microsoft heap dump noise
123     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
124     _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
125 #endif
126 #if _MSC_VER >= 1400
127     // Disable confusing "helpful" text message on abort, ctrl-c
128     _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
129 #endif
130 #ifndef __WXMSW__
131     umask(077);
132 #endif
133
134     //
135     // Parameters
136     //
137     ParseParameters(argc, argv);
138
139     if (mapArgs.count("-datadir"))
140     {
141         filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
142         strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
143     }
144
145     ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir
146
147     if (mapArgs.count("-?") || mapArgs.count("--help"))
148     {
149         string strUsage = string() +
150           _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
151             "  bitcoin [options]                   \t  " + "\n" +
152             "  bitcoin [options] <command> [params]\t  " + _("Send command to -server or bitcoind\n") +
153             "  bitcoin [options] help              \t\t  " + _("List commands\n") +
154             "  bitcoin [options] help <command>    \t\t  " + _("Get help for a command\n") +
155           _("Options:\n") +
156             "  -conf=<file>    \t  " + _("Specify configuration file (default: bitcoin.conf)\n") +
157             "  -gen            \t  " + _("Generate coins\n") +
158             "  -gen=0          \t  " + _("Don't generate coins\n") +
159             "  -min            \t  " + _("Start minimized\n") +
160             "  -datadir=<dir>  \t  " + _("Specify data directory\n") +
161             "  -proxy=<ip:port>\t  " + _("Connect through socks4 proxy\n") +
162             "  -addnode=<ip>   \t  " + _("Add a node to connect to\n") +
163             "  -connect=<ip>   \t  " + _("Connect only to the specified node\n") +
164             "  -server         \t  " + _("Accept command line and JSON-RPC commands\n") +
165             "  -daemon         \t  " + _("Run in the background as a daemon and accept commands\n") +
166             "  -?              \t  " + _("This help message\n");
167
168 #if defined(__WXMSW__) && defined(GUI)
169         // Tabs make the columns line up in the message box
170         wxMessageBox(strUsage, "Bitcoin", wxOK);
171 #else
172         // Remove tabs
173         strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
174         fprintf(stderr, "%s", strUsage.c_str());
175 #endif
176         return false;
177     }
178
179     if (mapArgs.count("-debug"))
180         fDebug = true;
181
182     if (mapArgs.count("-printtodebugger"))
183         fPrintToDebugger = true;
184
185     if (fCommandLine)
186     {
187         int ret = CommandLineRPC(argc, argv);
188         exit(ret);
189     }
190
191     if (!fDebug && !pszSetDataDir[0])
192         ShrinkDebugFile();
193     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
194     printf("Bitcoin version %d.%d.%d%s beta\n", VERSION/10000, (VERSION/100)%100, VERSION%100, pszSubVer);
195 #ifdef GUI
196     printf("OS version %s\n", ((string)wxGetOsDescription()).c_str());
197     printf("System default language is %d %s\n", g_locale.GetSystemLanguage(), ((string)g_locale.GetSysName()).c_str());
198     printf("Language file %s (%s)\n", (string("locale/") + (string)g_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)g_locale.GetLocale()).c_str());
199 #endif
200     printf("Default data directory %s\n", GetDefaultDataDir().c_str());
201
202     if (mapArgs.count("-loadblockindextest"))
203     {
204         CTxDB txdb("r");
205         txdb.LoadBlockIndex();
206         PrintBlockTree();
207         return false;
208     }
209
210     //
211     // Limit to single instance per user
212     // Required to protect the database files if we're going to keep deleting log.*
213     //
214 #if defined(__WXMSW__) && defined(GUI)
215     // todo: wxSingleInstanceChecker wasn't working on Linux, never deleted its lock file
216     //  maybe should go by whether successfully bind port 8333 instead
217     wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");
218     for (int i = 0; i < strMutexName.size(); i++)
219         if (!isalnum(strMutexName[i]))
220             strMutexName[i] = '.';
221     wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
222     if (psingleinstancechecker->IsAnotherRunning())
223     {
224         printf("Existing instance found\n");
225         unsigned int nStart = GetTime();
226         loop
227         {
228             // TODO: find out how to do this in Linux, or replace with wxWidgets commands
229             // Show the previous instance and exit
230             HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");
231             if (hwndPrev)
232             {
233                 if (IsIconic(hwndPrev))
234                     ShowWindow(hwndPrev, SW_RESTORE);
235                 SetForegroundWindow(hwndPrev);
236                 return false;
237             }
238
239             if (GetTime() > nStart + 60)
240                 return false;
241
242             // Resume this instance if the other exits
243             delete psingleinstancechecker;
244             Sleep(1000);
245             psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
246             if (!psingleinstancechecker->IsAnotherRunning())
247                 break;
248         }
249     }
250 #endif
251
252     // Bind to the port early so we can tell if another instance is already running.
253     // This is a backup to wxSingleInstanceChecker, which doesn't work on Linux.
254     string strErrors;
255     if (!BindListenPort(strErrors))
256     {
257         wxMessageBox(strErrors, "Bitcoin");
258         return false;
259     }
260
261     //
262     // Load data files
263     //
264     if (fDaemon)
265         fprintf(stdout, "bitcoin server starting\n");
266     strErrors = "";
267     int64 nStart;
268
269     printf("Loading addresses...\n");
270     nStart = GetTimeMillis();
271     if (!LoadAddresses())
272         strErrors += _("Error loading addr.dat      \n");
273     printf(" addresses   %15"PRI64d"ms\n", GetTimeMillis() - nStart);
274
275     printf("Loading block index...\n");
276     nStart = GetTimeMillis();
277     if (!LoadBlockIndex())
278         strErrors += _("Error loading blkindex.dat      \n");
279     printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
280
281     printf("Loading wallet...\n");
282     nStart = GetTimeMillis();
283     bool fFirstRun;
284     if (!LoadWallet(fFirstRun))
285         strErrors += _("Error loading wallet.dat      \n");
286     printf(" wallet      %15"PRI64d"ms\n", GetTimeMillis() - nStart);
287
288     printf("Done loading\n");
289
290         //// debug print
291         printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());
292         printf("nBestHeight = %d\n",            nBestHeight);
293         printf("mapKeys.size() = %d\n",         mapKeys.size());
294         printf("mapPubKeys.size() = %d\n",      mapPubKeys.size());
295         printf("mapWallet.size() = %d\n",       mapWallet.size());
296         printf("mapAddressBook.size() = %d\n",  mapAddressBook.size());
297
298     if (!strErrors.empty())
299     {
300         wxMessageBox(strErrors, "Bitcoin");
301         return false;
302     }
303
304     // Add wallet transactions that aren't already in a block to mapTransactions
305     ReacceptWalletTransactions();
306
307     //
308     // Parameters
309     //
310     if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree"))
311     {
312         PrintBlockTree();
313         return false;
314     }
315
316     if (mapArgs.count("-printblock"))
317     {
318         string strMatch = mapArgs["-printblock"];
319         int nFound = 0;
320         for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
321         {
322             uint256 hash = (*mi).first;
323             if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
324             {
325                 CBlockIndex* pindex = (*mi).second;
326                 CBlock block;
327                 block.ReadFromDisk(pindex);
328                 block.BuildMerkleTree();
329                 block.print();
330                 printf("\n");
331                 nFound++;
332             }
333         }
334         if (nFound == 0)
335             printf("No blocks matching %s were found\n", strMatch.c_str());
336         return false;
337     }
338
339     if (mapArgs.count("-gen"))
340     {
341         if (mapArgs["-gen"].empty())
342             fGenerateBitcoins = true;
343         else
344             fGenerateBitcoins = (atoi(mapArgs["-gen"].c_str()) != 0);
345     }
346
347     if (mapArgs.count("-proxy"))
348     {
349         fUseProxy = true;
350         addrProxy = CAddress(mapArgs["-proxy"]);
351         if (!addrProxy.IsValid())
352         {
353             wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
354             return false;
355         }
356     }
357
358     if (mapArgs.count("-addnode"))
359     {
360         foreach(string strAddr, mapMultiArgs["-addnode"])
361         {
362             CAddress addr(strAddr, NODE_NETWORK);
363             addr.nTime = 0; // so it won't relay unless successfully connected
364             if (addr.IsValid())
365                 AddAddress(addr);
366         }
367     }
368
369     if (mapArgs.count("-paytxfee"))
370     {
371         if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
372         {
373             wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
374             return false;
375         }
376     }
377
378     //
379     // Create the main window and start the node
380     //
381 #ifdef GUI
382     if (!fDaemon)
383         CreateMainWindow();
384 #endif
385
386     if (!CheckDiskSpace())
387         return false;
388
389     RandAddSeedPerfmon();
390
391     if (!CreateThread(StartNode, NULL))
392         wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
393
394     if (mapArgs.count("-server") || fDaemon)
395         CreateThread(ThreadRPCServer, NULL);
396
397 #if defined(__WXMSW__) && defined(GUI)
398     if (fFirstRun)
399         SetStartOnSystemStartup(true);
400 #endif
401
402     return true;
403 }