oracle driver converted to new API; fixed crash in libnxdb
[public/netxms.git] / src / server / netxmsd / netxmsd.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Server startup module
73869331 4** Copyright (C) 2003-2010 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
34
35//
36// Global data
37//
38
39BOOL g_bCheckDB = FALSE;
40
41
42//
43// Help text
44//
45
46static char help_text[]="NetXMS Server Version " NETXMS_VERSION_STRING "\n"
47 "Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 NetXMS Team\n\n"
48 "Usage: netxmsd [<options>]\n\n"
49 "Valid options are:\n"
50 " -e : Run database check on startup\n"
51 " -c <file> : Set non-default configuration file\n"
52 " : Default is " DEFAULT_CONFIG_FILE "\n"
53 " -d : Run as daemon/service\n"
54 " -D <level> : Set debug level (valid levels are 0..9)\n"
55 " -h : Display help and exit\n"
56#ifdef _WIN32
57 " -I : Install Windows service\n"
58 " -L <user> : Login name for service account.\n"
59 " -P <passwd> : Password for service account.\n"
60#else
61 " -p <file> : Specify pid file.\n"
62#endif
63#ifdef _WIN32
64 " -R : Remove Windows service\n"
65 " -s : Start Windows service\n"
66 " -S : Stop Windows service\n"
67#endif
68 " -v : Display version and exit\n"
69 "\n";
70
71
72//
5039dede
AK
73// Execute command and wait
74//
75
76static BOOL ExecAndWait(TCHAR *pszCommand)
77{
78 BOOL bSuccess = TRUE;
79
80#ifdef _WIN32
81 STARTUPINFO si;
82 PROCESS_INFORMATION pi;
83
84 // Fill in process startup info structure
85 memset(&si, 0, sizeof(STARTUPINFO));
86 si.cb = sizeof(STARTUPINFO);
87 si.dwFlags = 0;
88
89 // Create new process
90 if (!CreateProcess(NULL, pszCommand, NULL, NULL, FALSE,
91 IsStandalone() ? 0 : CREATE_NO_WINDOW | DETACHED_PROCESS,
92 NULL, NULL, &si, &pi))
93 {
94 bSuccess = FALSE;
95 }
96 else
97 {
98 WaitForSingleObject(pi.hProcess, INFINITE);
99
100 // Close all handles
101 CloseHandle(pi.hThread);
102 CloseHandle(pi.hProcess);
103 }
104#else
105 bSuccess = (system(pszCommand) != -1);
106#endif
107
108 return bSuccess;
109}
110
111
112//
113// Create minidump of given process
114//
115
116#ifdef _WIN32
117
118static void CreateMiniDump(DWORD pid)
119{
120 HANDLE hFile, hProcess;
121 TCHAR error[256];
122
123 printf("INFO: Starting minidump for process %d\n", pid);
124 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
125 if (hProcess != NULL)
126 {
127 hFile = CreateFile(_T("C:\\netxmsd.mdmp"), GENERIC_WRITE, 0, NULL,
128 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
129 if (hFile != INVALID_HANDLE_VALUE)
130 {
131 MiniDumpWriteDump(hProcess, pid, hFile, MiniDumpNormal, NULL, NULL, NULL);
132 CloseHandle(hFile);
133 printf("INFO: Minidump created successfully\n");
134 }
135 else
136 {
137 printf("ERROR: cannot create file for minidump (%s)\n", GetSystemErrorText(GetLastError(), error, 256));
138 }
139 }
140 else
141 {
142 printf("ERROR: cannot open process %d (%s)\n", pid, GetSystemErrorText(GetLastError(), error, 256));
143 }
144}
145
146#endif
147
148
149//
150// Parse command line
151// Returns TRUE on success and FALSE on failure
152//
153
154#ifdef _WIN32
155#define VALID_OPTIONS "c:CdD:ehIL:P:RsSv"
156#else
157#define VALID_OPTIONS "c:CdD:ehp:v"
158#endif
159
160static BOOL ParseCommandLine(int argc, char *argv[])
161{
162 int ch;
163 TCHAR *eptr;
164#ifdef _WIN32
165 char login[256] = "", password[256] = "", exePath[MAX_PATH], dllPath[MAX_PATH], *ptr;
166 BOOL useLogin = FALSE;
167#endif
168#if defined(_WIN32) || HAVE_DECL_GETOPT_LONG
169 static struct option longOptions[] =
170 {
171 { "check-db", 0, NULL, 'e' },
172 { "config", 1, NULL, 'c' },
173 { "daemon", 0, NULL, 'd' },
174 { "debug", 1, NULL, 'D' },
175 { "help", 0, NULL, 'h' },
176#ifdef _WIN32
177 { "check-service", 0, NULL, '!' },
178 { "dump", 1, NULL, '~' },
179 { "install", 0, NULL, 'I' },
180 { "login", 1, NULL, 'L' },
181 { "password", 1, NULL, 'P' },
182 { "remove", 0, NULL, 'R' },
183 { "start", 0, NULL, 's' },
184 { "stop", 0, NULL, 'S' },
185#else
186 { "pid-file", 1, NULL, 'p' },
187#endif
188 { NULL, 0, 0, 0 }
189 };
190#endif
191
192#if defined(_WIN32) || HAVE_DECL_GETOPT_LONG
193 while((ch = getopt_long(argc, argv, VALID_OPTIONS, longOptions, NULL)) != -1)
194#else
195 while((ch = getopt(argc, argv, VALID_OPTIONS)) != -1)
196#endif
197 {
198 switch(ch)
199 {
200 case 'h':
201 printf(help_text);
202 return FALSE;
203 case 'v':
204 printf("NetXMS Server Version " NETXMS_VERSION_STRING " Build of " __DATE__ "\n");
205 return FALSE;
206 case 'c':
207 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
208 break;
209 case 'C': // Check config
210 g_dwFlags &= ~AF_DAEMON;
211 printf("Checking configuration file (%s):\n\n", g_szConfigFile);
212 LoadConfig();
213 return FALSE;
214 case 'd':
215 g_dwFlags |= AF_DAEMON;
216 break;
217 case 'D': // Debug level
218 g_nDebugLevel = strtol(optarg, &eptr, 0);
219 if ((*eptr != 0) || (g_nDebugLevel < 0) || (g_nDebugLevel > 9))
220 {
221 printf("Invalid debug level \"%s\" - should be in range 0..9\n", optarg);
222 g_nDebugLevel = 0;
223 }
224 break;
225 case 'e':
226 g_bCheckDB = TRUE;
227 break;
228#ifdef _WIN32
229 case 'L':
230 nx_strncpy(login, optarg, 256);
231 useLogin = TRUE;
232 break;
233 case 'P':
234 nx_strncpy(password, optarg, 256);
235 break;
236 case 'I': // Install service
237 ptr = strrchr(argv[0], '\\');
238 if (ptr != NULL)
239 ptr++;
240 else
241 ptr = argv[0];
242
243 _fullpath(exePath, ptr, 255);
244
245 if (stricmp(&exePath[strlen(exePath)-4], ".exe"))
246 strcat(exePath, ".exe");
247 strcpy(dllPath, exePath);
248 ptr = strrchr(dllPath, '\\');
249 if (ptr != NULL) // Shouldn't be NULL
250 {
251 ptr++;
252 strcpy(ptr, "libnxsrv.dll");
253 }
254
255 InstallService(exePath, dllPath, useLogin ? login : NULL, useLogin ? password : NULL);
256 return FALSE;
257 case 'R': // Remove service
258 RemoveService();
259 return FALSE;
260 case 's': // Start service
261 StartCoreService();
262 return FALSE;
263 case 'S': // Stop service
264 StopCoreService();
265 return FALSE;
266 case '!': // Check service configuration (for migration from pre-0.2.20)
267 CheckServiceConfig();
268 return FALSE;
269 case '~':
270 CreateMiniDump(_tcstoul(optarg, NULL, 0));
271 return FALSE;
272#endif
273 default:
274 break;
275 }
276 }
277 return TRUE;
278}
279
280
281//
282// Startup code
283//
284
285int main(int argc, char *argv[])
286{
287#ifdef _WIN32
288 HKEY hKey;
289 DWORD dwSize;
290#else
291 int i;
292 FILE *fp;
293 char *pszEnv;
294#endif
295
296 InitThreadLibrary();
297
298#ifdef NETXMS_MEMORY_DEBUG
299 InitMemoryDebugger();
300#endif
301
302 // Check for alternate config file location
303#ifdef _WIN32
304 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Server"), 0,
305 KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
306 {
307 dwSize = MAX_PATH * sizeof(TCHAR);
308 RegQueryValueEx(hKey, _T("ConfigFile"), NULL, NULL, (BYTE *)g_szConfigFile, &dwSize);
309 RegCloseKey(hKey);
310 }
311#else
312 pszEnv = getenv("NETXMSD_CONFIG");
313 if (pszEnv != NULL)
314 nx_strncpy(g_szConfigFile, pszEnv, MAX_PATH);
315#endif
316
317 if (!ParseCommandLine(argc, argv))
318 return 1;
319
320 if (!LoadConfig())
321 {
322 if (IsStandalone())
323 printf("Error loading configuration file\n");
324 return 1;
325 }
326
327 // Set exception handler
328#ifdef _WIN32
329 if (g_dwFlags & AF_CATCH_EXCEPTIONS)
4262c0dc 330 SetExceptionHandler(SEHServiceExceptionHandler, SEHServiceExceptionDataWriter,
cbc777ee 331 g_szDumpDir, "netxmsd", MSG_EXCEPTION, g_dwFlags & AF_WRITE_FULL_DUMP, IsStandalone());
5039dede
AK
332 __try {
333#endif
334
335 // Check database before start if requested
336 if (g_bCheckDB)
337 {
338 char szCmd[MAX_PATH + 128], *pszSep;
339
340 strncpy(szCmd, argv[0], MAX_PATH);
341 pszSep = strrchr(szCmd, FS_PATH_SEPARATOR[0]);
342 if (pszSep != NULL)
343 pszSep++;
344 else
345 pszSep = szCmd;
346 sprintf(pszSep, "nxdbmgr -c \"%s\" -f check", g_szConfigFile);
347 if (!ExecAndWait(szCmd))
348 if (IsStandalone())
349 printf("ERROR: Failed to execute command \"%s\"\n", szCmd);
350 }
351
352#ifdef _WIN32
353 if (!IsStandalone())
354 {
355 InitService();
356 }
357 else
358 {
359 if (!Initialize())
360 {
361 printf("NetXMS Core initialization failed\n");
362
363 // Remove database lock
364 if (g_dwFlags & AF_DB_LOCKED)
365 {
366 UnlockDB();
367 ShutdownDB();
368 }
369 return 3;
370 }
371 Main(NULL);
372 }
373#else /* not _WIN32 */
374 if (!IsStandalone())
375 {
376 if (daemon(0, 0) == -1)
377 {
378 perror("Call to daemon() failed");
379 return 2;
380 }
381 }
382
383 // Write PID file
384 fp = fopen(g_szPIDFile, "w");
385 if (fp != NULL)
386 {
387 fprintf(fp, "%d", getpid());
388 fclose(fp);
389 }
390
391 // Initialize server
392 if (!Initialize())
393 {
394 // Remove database lock
395 if (g_dwFlags & AF_DB_LOCKED)
396 {
397 UnlockDB();
398 ShutdownDB();
399 }
400 return 3;
401 }
402
403 // Everything is OK, start common main loop
404 StartMainLoop(SignalHandler, Main);
405#endif /* _WIN32 */
406
407#ifdef _WIN32
408 LIBNETXMS_EXCEPTION_HANDLER
409#endif
410 return 0;
411}