added option enable-werror
[public/netxms.git] / src / server / netxmsd / netxmsd.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Server startup module
1621a079 4** Copyright (C) 2003-2011 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
5039dede
AK
38
39//
40// Global data
41//
42
43BOOL g_bCheckDB = FALSE;
44
45
46//
47// Help text
48//
49
e0f99bf0
VK
50static TCHAR help_text[] = _T("NetXMS Server Version ") NETXMS_VERSION_STRING _T("\n")
51 _T("Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 NetXMS Team\n\n")
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")
59 _T(" -h : Display help and exit\n")
5039dede 60#ifdef _WIN32
e0f99bf0
VK
61 _T(" -I : Install Windows service\n")
62 _T(" -L <user> : Login name for service account.\n")
63 _T(" -P <passwd> : Password for service account.\n")
5039dede 64#else
e0f99bf0 65 _T(" -p <file> : Specify pid file.\n")
5039dede
AK
66#endif
67#ifdef _WIN32
e0f99bf0
VK
68 _T(" -R : Remove Windows service\n")
69 _T(" -s : Start Windows service\n")
70 _T(" -S : Stop Windows service\n")
5039dede 71#endif
e0f99bf0
VK
72 _T(" -v : Display version and exit\n")
73 _T("\n");
5039dede
AK
74
75
76//
5039dede
AK
77// Execute command and wait
78//
79
e0f99bf0 80static BOOL ExecAndWait(char *pszCommand)
5039dede
AK
81{
82 BOOL bSuccess = TRUE;
83
84#ifdef _WIN32
e0f99bf0 85 STARTUPINFOA si;
5039dede
AK
86 PROCESS_INFORMATION pi;
87
88 // Fill in process startup info structure
977e7d9d
VK
89 memset(&si, 0, sizeof(STARTUPINFOA));
90 si.cb = sizeof(STARTUPINFOA);
5039dede
AK
91 si.dwFlags = 0;
92
93 // Create new process
e0f99bf0
VK
94 if (!CreateProcessA(NULL, pszCommand, NULL, NULL, FALSE,
95 IsStandalone() ? 0 : CREATE_NO_WINDOW | DETACHED_PROCESS,
96 NULL, NULL, &si, &pi))
5039dede
AK
97 {
98 bSuccess = FALSE;
99 }
100 else
101 {
102 WaitForSingleObject(pi.hProcess, INFINITE);
103
104 // Close all handles
105 CloseHandle(pi.hThread);
106 CloseHandle(pi.hProcess);
107 }
108#else
109 bSuccess = (system(pszCommand) != -1);
110#endif
111
112 return bSuccess;
113}
114
115
116//
117// Create minidump of given process
118//
119
120#ifdef _WIN32
121
122static void CreateMiniDump(DWORD pid)
123{
124 HANDLE hFile, hProcess;
125 TCHAR error[256];
126
e0f99bf0 127 _tprintf(_T("INFO: Starting minidump for process %d\n"), pid);
5039dede
AK
128 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
129 if (hProcess != NULL)
130 {
131 hFile = CreateFile(_T("C:\\netxmsd.mdmp"), GENERIC_WRITE, 0, NULL,
132 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
133 if (hFile != INVALID_HANDLE_VALUE)
134 {
135 MiniDumpWriteDump(hProcess, pid, hFile, MiniDumpNormal, NULL, NULL, NULL);
136 CloseHandle(hFile);
e0f99bf0 137 _tprintf(_T("INFO: Minidump created successfully\n"));
5039dede
AK
138 }
139 else
140 {
e0f99bf0 141 _tprintf(_T("ERROR: cannot create file for minidump (%s)\n"), GetSystemErrorText(GetLastError(), error, 256));
5039dede
AK
142 }
143 }
144 else
145 {
e0f99bf0 146 _tprintf(_T("ERROR: cannot open process %d (%s)\n"), pid, GetSystemErrorText(GetLastError(), error, 256));
5039dede
AK
147 }
148}
149
150#endif
151
152
153//
154// Parse command line
155// Returns TRUE on success and FALSE on failure
156//
157
158#ifdef _WIN32
159#define VALID_OPTIONS "c:CdD:ehIL:P:RsSv"
160#else
161#define VALID_OPTIONS "c:CdD:ehp:v"
162#endif
163
164static BOOL ParseCommandLine(int argc, char *argv[])
165{
166 int ch;
e0f99bf0 167 char *eptr;
5039dede 168#ifdef _WIN32
e0f99bf0
VK
169 TCHAR login[256] = _T(""), password[256] = _T("");
170 char exePath[MAX_PATH], dllPath[MAX_PATH], *ptr;
5039dede
AK
171 BOOL useLogin = FALSE;
172#endif
173#if defined(_WIN32) || HAVE_DECL_GETOPT_LONG
174 static struct option longOptions[] =
175 {
176 { "check-db", 0, NULL, 'e' },
177 { "config", 1, NULL, 'c' },
178 { "daemon", 0, NULL, 'd' },
179 { "debug", 1, NULL, 'D' },
180 { "help", 0, NULL, 'h' },
181#ifdef _WIN32
182 { "check-service", 0, NULL, '!' },
183 { "dump", 1, NULL, '~' },
184 { "install", 0, NULL, 'I' },
185 { "login", 1, NULL, 'L' },
186 { "password", 1, NULL, 'P' },
187 { "remove", 0, NULL, 'R' },
188 { "start", 0, NULL, 's' },
189 { "stop", 0, NULL, 'S' },
190#else
c601fc15 191 { "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
228 g_nDebugLevel = strtol(optarg, &eptr, 0);
229 if ((*eptr != 0) || (g_nDebugLevel < 0) || (g_nDebugLevel > 9))
230 {
e0f99bf0 231 _tprintf(_T("Invalid debug level \"%hs\" - should be in range 0..9\n"), optarg);
5039dede
AK
232 g_nDebugLevel = 0;
233 }
234 break;
235 case 'e':
236 g_bCheckDB = TRUE;
237 break;
238#ifdef _WIN32
239 case 'L':
e0f99bf0
VK
240#ifdef UNICODE
241 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, login, 256);
242 login[255] = 0;
243#else
5039dede 244 nx_strncpy(login, optarg, 256);
e0f99bf0 245#endif
5039dede
AK
246 useLogin = TRUE;
247 break;
248 case 'P':
e0f99bf0
VK
249#ifdef UNICODE
250 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, password, 256);
251 password[255] = 0;
252#else
5039dede 253 nx_strncpy(password, optarg, 256);
e0f99bf0 254#endif
5039dede
AK
255 break;
256 case 'I': // Install service
257 ptr = strrchr(argv[0], '\\');
258 if (ptr != NULL)
259 ptr++;
260 else
261 ptr = argv[0];
262
263 _fullpath(exePath, ptr, 255);
264
265 if (stricmp(&exePath[strlen(exePath)-4], ".exe"))
266 strcat(exePath, ".exe");
267 strcpy(dllPath, exePath);
268 ptr = strrchr(dllPath, '\\');
269 if (ptr != NULL) // Shouldn't be NULL
270 {
271 ptr++;
272 strcpy(ptr, "libnxsrv.dll");
273 }
e0f99bf0
VK
274#ifdef UNICODE
275 WCHAR wexePath[MAX_PATH], wdllPath[MAX_PATH];
276 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, exePath, -1, wexePath, MAX_PATH);
277 wexePath[MAX_PATH - 1] = 0;
278 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, dllPath, -1, wdllPath, MAX_PATH);
279 wdllPath[MAX_PATH - 1] = 0;
280 InstallService(wexePath, wdllPath, useLogin ? login : NULL, useLogin ? password : NULL);
281#else
5039dede 282 InstallService(exePath, dllPath, useLogin ? login : NULL, useLogin ? password : NULL);
e0f99bf0 283#endif
5039dede
AK
284 return FALSE;
285 case 'R': // Remove service
286 RemoveService();
287 return FALSE;
288 case 's': // Start service
289 StartCoreService();
290 return FALSE;
291 case 'S': // Stop service
292 StopCoreService();
293 return FALSE;
294 case '!': // Check service configuration (for migration from pre-0.2.20)
295 CheckServiceConfig();
296 return FALSE;
297 case '~':
e0f99bf0 298 CreateMiniDump(strtoul(optarg, NULL, 0));
5039dede
AK
299 return FALSE;
300#endif
301 default:
302 break;
303 }
304 }
305 return TRUE;
306}
307
308
309//
310// Startup code
311//
312
313int main(int argc, char *argv[])
314{
315#ifdef _WIN32
316 HKEY hKey;
317 DWORD dwSize;
318#else
319 int i;
320 FILE *fp;
c601fc15 321 TCHAR *pszEnv;
5039dede
AK
322#endif
323
44cdd527
VK
324#ifdef __sun
325 signal(SIGPIPE, SIG_IGN);
326 signal(SIGHUP, SIG_IGN);
327 signal(SIGINT, SIG_IGN);
328 signal(SIGQUIT, SIG_IGN);
329 signal(SIGUSR1, SIG_IGN);
330 signal(SIGUSR2, SIG_IGN);
331#endif
332
5039dede
AK
333 InitThreadLibrary();
334
335#ifdef NETXMS_MEMORY_DEBUG
336 InitMemoryDebugger();
337#endif
338
339 // Check for alternate config file location
340#ifdef _WIN32
42acd918 341 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Server"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
5039dede
AK
342 {
343 dwSize = MAX_PATH * sizeof(TCHAR);
344 RegQueryValueEx(hKey, _T("ConfigFile"), NULL, NULL, (BYTE *)g_szConfigFile, &dwSize);
345 RegCloseKey(hKey);
346 }
347#else
82d4fb3d 348 pszEnv = _tgetenv(_T("NETXMSD_CONFIG"));
5039dede
AK
349 if (pszEnv != NULL)
350 nx_strncpy(g_szConfigFile, pszEnv, MAX_PATH);
351#endif
352
353 if (!ParseCommandLine(argc, argv))
354 return 1;
355
356 if (!LoadConfig())
357 {
358 if (IsStandalone())
e0f99bf0 359 _tprintf(_T("Error loading configuration file\n"));
5039dede
AK
360 return 1;
361 }
362
363 // Set exception handler
364#ifdef _WIN32
365 if (g_dwFlags & AF_CATCH_EXCEPTIONS)
4262c0dc 366 SetExceptionHandler(SEHServiceExceptionHandler, SEHServiceExceptionDataWriter,
e0f99bf0 367 g_szDumpDir, _T("netxmsd"), MSG_EXCEPTION, g_dwFlags & AF_WRITE_FULL_DUMP, IsStandalone());
5039dede
AK
368 __try {
369#endif
370
712dd47d
VK
371 // Fix path to Java VM
372#ifdef _WIN32
373 if (!_tcscmp(g_szJavaPath, _T("java")))
374 {
375 TCHAR path[MAX_PATH];
376
377 if (GetModuleFileName(NULL, path, MAX_PATH) != 0)
378 {
379 TCHAR *p = _tcsrchr(path, _T('\\'));
380 if (p != NULL)
381 {
382 p--;
383 p = _tcsrchr(p, _T('\\'));
384 if (p != NULL)
385 {
386 p++;
387 _tcscpy(p, _T("jre\\bin\\java.exe"));
388 if (_taccess(path, 4))
389 {
390 _tcscpy(g_szJavaPath, path);
391 }
392 }
393 }
394 }
395 }
396#endif
397
5039dede
AK
398 // Check database before start if requested
399 if (g_bCheckDB)
400 {
401 char szCmd[MAX_PATH + 128], *pszSep;
402
403 strncpy(szCmd, argv[0], MAX_PATH);
404 pszSep = strrchr(szCmd, FS_PATH_SEPARATOR[0]);
405 if (pszSep != NULL)
406 pszSep++;
407 else
408 pszSep = szCmd;
e0f99bf0
VK
409#ifdef UNICODE
410 snprintf(pszSep, 128, "nxdbmgr -c \"%S\" -f check", g_szConfigFile);
411#else
412 snprintf(pszSep, 128, "nxdbmgr -c \"%s\" -f check", g_szConfigFile);
413#endif
5039dede
AK
414 if (!ExecAndWait(szCmd))
415 if (IsStandalone())
e0f99bf0 416 _tprintf(_T("ERROR: Failed to execute command \"%hs\"\n"), szCmd);
5039dede
AK
417 }
418
419#ifdef _WIN32
420 if (!IsStandalone())
421 {
422 InitService();
423 }
424 else
425 {
426 if (!Initialize())
427 {
e0f99bf0 428 _tprintf(_T("NetXMS Core initialization failed\n"));
5039dede
AK
429
430 // Remove database lock
431 if (g_dwFlags & AF_DB_LOCKED)
432 {
433 UnlockDB();
434 ShutdownDB();
435 }
436 return 3;
437 }
438 Main(NULL);
439 }
440#else /* not _WIN32 */
441 if (!IsStandalone())
442 {
443 if (daemon(0, 0) == -1)
444 {
445 perror("Call to daemon() failed");
446 return 2;
447 }
448 }
449
450 // Write PID file
e0f99bf0 451 fp = _tfopen(g_szPIDFile, _T("w"));
5039dede
AK
452 if (fp != NULL)
453 {
e0f99bf0 454 _ftprintf(fp, _T("%d"), getpid());
5039dede
AK
455 fclose(fp);
456 }
457
458 // Initialize server
459 if (!Initialize())
460 {
461 // Remove database lock
462 if (g_dwFlags & AF_DB_LOCKED)
463 {
464 UnlockDB();
465 ShutdownDB();
466 }
467 return 3;
468 }
469
470 // Everything is OK, start common main loop
471 StartMainLoop(SignalHandler, Main);
472#endif /* _WIN32 */
473
474#ifdef _WIN32
475 LIBNETXMS_EXCEPTION_HANDLER
476#endif
477 return 0;
478}