DB2 subagent continued.
[public/netxms.git] / src / server / netxmsd / netxmsd.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Server startup module
ed950274 4** Copyright (C) 2003-2013 NetXMS Team
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: netxmsd.cpp
21**
22**/
23
24#include "netxmsd.h"
25
26#if HAVE_GETOPT_H
27#include <getopt.h>
28#endif
29
30#ifdef _WIN32
31#include <dbghelp.h>
32#endif
33
44cdd527
VK
34#ifdef __sun
35#include <signal.h>
36#endif
37
d27e7413 38#if defined(_WITH_ENCRYPTION) && defined(_WIN32)
958a9397
VK
39#include <openssl/applink.c>
40#endif
41
f375019e
VK
42/**
43 * Global data
44 */
5039dede
AK
45BOOL g_bCheckDB = FALSE;
46
f375019e
VK
47/**
48 * Help text
49 */
e0f99bf0 50static TCHAR help_text[] = _T("NetXMS Server Version ") NETXMS_VERSION_STRING _T("\n")
f375019e 51 _T("Copyright (c) 2003-2013 NetXMS Team\n\n")
e0f99bf0
VK
52 _T("Usage: netxmsd [<options>]\n\n")
53 _T("Valid options are:\n")
54 _T(" -e : Run database check on startup\n")
55 _T(" -c <file> : Set non-default configuration file\n")
56 _T(" : Default is ") DEFAULT_CONFIG_FILE _T("\n")
57 _T(" -d : Run as daemon/service\n")
58 _T(" -D <level> : Set debug level (valid levels are 0..9)\n")
8782d780 59 _T(" -q : Disable interactive console\n")
e0f99bf0 60 _T(" -h : Display help and exit\n")
5039dede 61#ifdef _WIN32
e0f99bf0
VK
62 _T(" -I : Install Windows service\n")
63 _T(" -L <user> : Login name for service account.\n")
64 _T(" -P <passwd> : Password for service account.\n")
5039dede 65#else
e0f99bf0 66 _T(" -p <file> : Specify pid file.\n")
5039dede
AK
67#endif
68#ifdef _WIN32
e0f99bf0
VK
69 _T(" -R : Remove Windows service\n")
70 _T(" -s : Start Windows service\n")
71 _T(" -S : Stop Windows service\n")
5039dede 72#endif
e0f99bf0
VK
73 _T(" -v : Display version and exit\n")
74 _T("\n");
5039dede 75
f375019e
VK
76/**
77 * Execute command and wait
78 */
e0f99bf0 79static BOOL ExecAndWait(char *pszCommand)
5039dede
AK
80{
81 BOOL bSuccess = TRUE;
82
83#ifdef _WIN32
e0f99bf0 84 STARTUPINFOA si;
5039dede
AK
85 PROCESS_INFORMATION pi;
86
87 // Fill in process startup info structure
977e7d9d
VK
88 memset(&si, 0, sizeof(STARTUPINFOA));
89 si.cb = sizeof(STARTUPINFOA);
5039dede
AK
90 si.dwFlags = 0;
91
92 // Create new process
e0f99bf0
VK
93 if (!CreateProcessA(NULL, pszCommand, NULL, NULL, FALSE,
94 IsStandalone() ? 0 : CREATE_NO_WINDOW | DETACHED_PROCESS,
95 NULL, NULL, &si, &pi))
5039dede
AK
96 {
97 bSuccess = FALSE;
98 }
99 else
100 {
101 WaitForSingleObject(pi.hProcess, INFINITE);
102
103 // Close all handles
104 CloseHandle(pi.hThread);
105 CloseHandle(pi.hProcess);
106 }
107#else
108 bSuccess = (system(pszCommand) != -1);
109#endif
110
111 return bSuccess;
112}
113
114
115//
116// Create minidump of given process
117//
118
119#ifdef _WIN32
120
121static void CreateMiniDump(DWORD pid)
122{
123 HANDLE hFile, hProcess;
124 TCHAR error[256];
125
e0f99bf0 126 _tprintf(_T("INFO: Starting minidump for process %d\n"), pid);
5039dede
AK
127 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
128 if (hProcess != NULL)
129 {
130 hFile = CreateFile(_T("C:\\netxmsd.mdmp"), GENERIC_WRITE, 0, NULL,
131 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
132 if (hFile != INVALID_HANDLE_VALUE)
133 {
134 MiniDumpWriteDump(hProcess, pid, hFile, MiniDumpNormal, NULL, NULL, NULL);
135 CloseHandle(hFile);
e0f99bf0 136 _tprintf(_T("INFO: Minidump created successfully\n"));
5039dede
AK
137 }
138 else
139 {
e0f99bf0 140 _tprintf(_T("ERROR: cannot create file for minidump (%s)\n"), GetSystemErrorText(GetLastError(), error, 256));
5039dede
AK
141 }
142 }
143 else
144 {
e0f99bf0 145 _tprintf(_T("ERROR: cannot open process %d (%s)\n"), pid, GetSystemErrorText(GetLastError(), error, 256));
5039dede
AK
146 }
147}
148
149#endif
150
151
152//
153// Parse command line
154// Returns TRUE on success and FALSE on failure
155//
156
157#ifdef _WIN32
8782d780 158#define VALID_OPTIONS "c:CdD:qehIL:P:RsSv"
5039dede 159#else
8782d780 160#define VALID_OPTIONS "c:CdD:qehp:v"
5039dede
AK
161#endif
162
163static BOOL ParseCommandLine(int argc, char *argv[])
164{
165 int ch;
e0f99bf0 166 char *eptr;
5039dede 167#ifdef _WIN32
e0f99bf0
VK
168 TCHAR login[256] = _T(""), password[256] = _T("");
169 char exePath[MAX_PATH], dllPath[MAX_PATH], *ptr;
5039dede
AK
170 BOOL useLogin = FALSE;
171#endif
172#if defined(_WIN32) || HAVE_DECL_GETOPT_LONG
173 static struct option longOptions[] =
174 {
0b8da006
AK
175 { (char *)"check-db", 0, NULL, 'e' },
176 { (char *)"config", 1, NULL, 'c' },
177 { (char *)"daemon", 0, NULL, 'd' },
178 { (char *)"debug", 1, NULL, 'D' },
179 { (char *)"help", 0, NULL, 'h' },
8782d780 180 { (char *)"quiet", 1, NULL, 'q' },
5039dede 181#ifdef _WIN32
0b8da006
AK
182 { (char *)"check-service", 0, NULL, '!' },
183 { (char *)"dump", 1, NULL, '~' },
184 { (char *)"install", 0, NULL, 'I' },
185 { (char *)"login", 1, NULL, 'L' },
186 { (char *)"password", 1, NULL, 'P' },
187 { (char *)"remove", 0, NULL, 'R' },
188 { (char *)"start", 0, NULL, 's' },
189 { (char *)"stop", 0, NULL, 'S' },
5039dede 190#else
0b8da006 191 { (char *)"pid-file", 1, NULL, 'p' },
5039dede
AK
192#endif
193 { NULL, 0, 0, 0 }
194 };
195#endif
196
197#if defined(_WIN32) || HAVE_DECL_GETOPT_LONG
198 while((ch = getopt_long(argc, argv, VALID_OPTIONS, longOptions, NULL)) != -1)
199#else
200 while((ch = getopt(argc, argv, VALID_OPTIONS)) != -1)
201#endif
202 {
203 switch(ch)
204 {
205 case 'h':
e0f99bf0 206 _tprintf(help_text);
5039dede
AK
207 return FALSE;
208 case 'v':
e0f99bf0 209 _tprintf(_T("NetXMS Server Version ") NETXMS_VERSION_STRING _T(" Build of %hs\n"), __DATE__);
5039dede
AK
210 return FALSE;
211 case 'c':
e0f99bf0
VK
212#ifdef UNICODE
213 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szConfigFile, MAX_PATH);
214 g_szConfigFile[MAX_PATH - 1] = 0;
215#else
5039dede 216 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
e0f99bf0 217#endif
5039dede
AK
218 break;
219 case 'C': // Check config
220 g_dwFlags &= ~AF_DAEMON;
e0f99bf0 221 _tprintf(_T("Checking configuration file (%s):\n\n"), g_szConfigFile);
5039dede
AK
222 LoadConfig();
223 return FALSE;
224 case 'd':
225 g_dwFlags |= AF_DAEMON;
226 break;
227 case 'D': // Debug level
ed950274
VK
228 g_debugLevel = strtoul(optarg, &eptr, 0);
229 if ((*eptr != 0) || (g_debugLevel > 9))
5039dede 230 {
e0f99bf0 231 _tprintf(_T("Invalid debug level \"%hs\" - should be in range 0..9\n"), optarg);
ed950274 232 g_debugLevel = 0;
5039dede
AK
233 }
234 break;
3a82d5ae
VK
235 case 'q': // disable interactive console
236 g_dwFlags |= AF_DEBUG_CONSOLE_DISABLED;
237 break;
5039dede
AK
238 case 'e':
239 g_bCheckDB = TRUE;
240 break;
241#ifdef _WIN32
242 case 'L':
e0f99bf0
VK
243#ifdef UNICODE
244 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, login, 256);
245 login[255] = 0;
246#else
5039dede 247 nx_strncpy(login, optarg, 256);
e0f99bf0 248#endif
5039dede
AK
249 useLogin = TRUE;
250 break;
251 case 'P':
e0f99bf0
VK
252#ifdef UNICODE
253 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, password, 256);
254 password[255] = 0;
255#else
5039dede 256 nx_strncpy(password, optarg, 256);
e0f99bf0 257#endif
5039dede
AK
258 break;
259 case 'I': // Install service
260 ptr = strrchr(argv[0], '\\');
261 if (ptr != NULL)
262 ptr++;
263 else
264 ptr = argv[0];
265
266 _fullpath(exePath, ptr, 255);
267
268 if (stricmp(&exePath[strlen(exePath)-4], ".exe"))
269 strcat(exePath, ".exe");
270 strcpy(dllPath, exePath);
271 ptr = strrchr(dllPath, '\\');
272 if (ptr != NULL) // Shouldn't be NULL
273 {
274 ptr++;
275 strcpy(ptr, "libnxsrv.dll");
276 }
e0f99bf0
VK
277#ifdef UNICODE
278 WCHAR wexePath[MAX_PATH], wdllPath[MAX_PATH];
279 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, exePath, -1, wexePath, MAX_PATH);
280 wexePath[MAX_PATH - 1] = 0;
281 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, dllPath, -1, wdllPath, MAX_PATH);
282 wdllPath[MAX_PATH - 1] = 0;
283 InstallService(wexePath, wdllPath, useLogin ? login : NULL, useLogin ? password : NULL);
284#else
5039dede 285 InstallService(exePath, dllPath, useLogin ? login : NULL, useLogin ? password : NULL);
e0f99bf0 286#endif
5039dede
AK
287 return FALSE;
288 case 'R': // Remove service
289 RemoveService();
290 return FALSE;
291 case 's': // Start service
292 StartCoreService();
293 return FALSE;
294 case 'S': // Stop service
295 StopCoreService();
296 return FALSE;
297 case '!': // Check service configuration (for migration from pre-0.2.20)
298 CheckServiceConfig();
299 return FALSE;
300 case '~':
e0f99bf0 301 CreateMiniDump(strtoul(optarg, NULL, 0));
5039dede
AK
302 return FALSE;
303#endif
304 default:
305 break;
306 }
307 }
308 return TRUE;
309}
310
311
312//
313// Startup code
314//
315
316int main(int argc, char *argv[])
317{
318#ifdef _WIN32
319 HKEY hKey;
320 DWORD dwSize;
321#else
322 int i;
323 FILE *fp;
c601fc15 324 TCHAR *pszEnv;
5039dede
AK
325#endif
326
d40b6356 327#if defined(__sun) || defined(_AIX) || defined(__hpux)
44cdd527
VK
328 signal(SIGPIPE, SIG_IGN);
329 signal(SIGHUP, SIG_IGN);
330 signal(SIGINT, SIG_IGN);
331 signal(SIGQUIT, SIG_IGN);
332 signal(SIGUSR1, SIG_IGN);
333 signal(SIGUSR2, SIG_IGN);
334#endif
335
5039dede
AK
336 InitThreadLibrary();
337
338#ifdef NETXMS_MEMORY_DEBUG
339 InitMemoryDebugger();
340#endif
341
342 // Check for alternate config file location
343#ifdef _WIN32
42acd918 344 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Server"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
5039dede
AK
345 {
346 dwSize = MAX_PATH * sizeof(TCHAR);
347 RegQueryValueEx(hKey, _T("ConfigFile"), NULL, NULL, (BYTE *)g_szConfigFile, &dwSize);
348 RegCloseKey(hKey);
349 }
350#else
82d4fb3d 351 pszEnv = _tgetenv(_T("NETXMSD_CONFIG"));
5039dede
AK
352 if (pszEnv != NULL)
353 nx_strncpy(g_szConfigFile, pszEnv, MAX_PATH);
354#endif
355
356 if (!ParseCommandLine(argc, argv))
357 return 1;
358
359 if (!LoadConfig())
360 {
361 if (IsStandalone())
e0f99bf0 362 _tprintf(_T("Error loading configuration file\n"));
5039dede
AK
363 return 1;
364 }
365
366 // Set exception handler
367#ifdef _WIN32
368 if (g_dwFlags & AF_CATCH_EXCEPTIONS)
4262c0dc 369 SetExceptionHandler(SEHServiceExceptionHandler, SEHServiceExceptionDataWriter,
e0f99bf0 370 g_szDumpDir, _T("netxmsd"), MSG_EXCEPTION, g_dwFlags & AF_WRITE_FULL_DUMP, IsStandalone());
5039dede
AK
371 __try {
372#endif
373
712dd47d
VK
374 // Fix path to Java VM
375#ifdef _WIN32
376 if (!_tcscmp(g_szJavaPath, _T("java")))
377 {
378 TCHAR path[MAX_PATH];
379
380 if (GetModuleFileName(NULL, path, MAX_PATH) != 0)
381 {
382 TCHAR *p = _tcsrchr(path, _T('\\'));
383 if (p != NULL)
384 {
385 p--;
386 p = _tcsrchr(p, _T('\\'));
387 if (p != NULL)
388 {
389 p++;
390 _tcscpy(p, _T("jre\\bin\\java.exe"));
391 if (_taccess(path, 4))
392 {
393 _tcscpy(g_szJavaPath, path);
394 }
395 }
396 }
397 }
398 }
399#endif
400
5039dede
AK
401 // Check database before start if requested
402 if (g_bCheckDB)
403 {
404 char szCmd[MAX_PATH + 128], *pszSep;
405
406 strncpy(szCmd, argv[0], MAX_PATH);
407 pszSep = strrchr(szCmd, FS_PATH_SEPARATOR[0]);
408 if (pszSep != NULL)
409 pszSep++;
410 else
411 pszSep = szCmd;
e0f99bf0
VK
412#ifdef UNICODE
413 snprintf(pszSep, 128, "nxdbmgr -c \"%S\" -f check", g_szConfigFile);
414#else
415 snprintf(pszSep, 128, "nxdbmgr -c \"%s\" -f check", g_szConfigFile);
416#endif
5039dede
AK
417 if (!ExecAndWait(szCmd))
418 if (IsStandalone())
e0f99bf0 419 _tprintf(_T("ERROR: Failed to execute command \"%hs\"\n"), szCmd);
5039dede
AK
420 }
421
422#ifdef _WIN32
423 if (!IsStandalone())
424 {
425 InitService();
426 }
427 else
428 {
429 if (!Initialize())
430 {
e0f99bf0 431 _tprintf(_T("NetXMS Core initialization failed\n"));
5039dede
AK
432
433 // Remove database lock
434 if (g_dwFlags & AF_DB_LOCKED)
435 {
436 UnlockDB();
437 ShutdownDB();
438 }
439 return 3;
440 }
441 Main(NULL);
442 }
443#else /* not _WIN32 */
444 if (!IsStandalone())
445 {
446 if (daemon(0, 0) == -1)
447 {
448 perror("Call to daemon() failed");
449 return 2;
450 }
451 }
452
453 // Write PID file
e0f99bf0 454 fp = _tfopen(g_szPIDFile, _T("w"));
5039dede
AK
455 if (fp != NULL)
456 {
e0f99bf0 457 _ftprintf(fp, _T("%d"), getpid());
5039dede
AK
458 fclose(fp);
459 }
460
461 // Initialize server
462 if (!Initialize())
463 {
464 // Remove database lock
465 if (g_dwFlags & AF_DB_LOCKED)
466 {
467 UnlockDB();
468 ShutdownDB();
469 }
470 return 3;
471 }
472
473 // Everything is OK, start common main loop
474 StartMainLoop(SignalHandler, Main);
475#endif /* _WIN32 */
476
477#ifdef _WIN32
478 LIBNETXMS_EXCEPTION_HANDLER
479#endif
480 return 0;
481}