added support for id attribute in config tags
[public/netxms.git] / src / agent / core / nxagentd.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS multiplatform core agent
9fcdfda7 3** Copyright (C) 2003-2009 Victor Kirhenshtein
5039dede
AK
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be usefu,,
11** but ITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** File: nxagentd.cpp
20**
21**/
22
23#include "nxagentd.h"
24
25#if defined(_WIN32)
26#include <conio.h>
27#include <locale.h>
28#elif defined(_NETWARE)
29#include <screen.h>
30#include <library.h>
31#else
32#include <signal.h>
33#include <sys/wait.h>
34#endif
35
36#if HAVE_SYS_UTSNAME_H
37#include <sys/utsname.h>
38#endif
39
40#if HAVE_SYS_SYSCTL_H
41#include <sys/sysctl.h>
42#endif
43
44
45//
46// Externals
47//
48
49THREAD_RESULT THREAD_CALL ListenerThread(void *);
50THREAD_RESULT THREAD_CALL SessionWatchdog(void *);
51THREAD_RESULT THREAD_CALL TrapSender(void *);
52
53void ShutdownTrapSender();
54
9fcdfda7
VK
55void StartWatchdog();
56void StopWatchdog();
57int WatchdogMain(DWORD pid);
58
5039dede
AK
59#if !defined(_WIN32) && !defined(_NETWARE)
60void InitStaticSubagents(void);
61#endif
62
9f96fc88
VK
63#ifdef _WIN32
64extern TCHAR g_windowsServiceName[];
65extern TCHAR g_windowsServiceDisplayName[];
66#endif
67
5039dede
AK
68
69//
70// Messages generated by mc.pl (for UNIX version only)
71//
72
73#ifndef _WIN32
74extern unsigned int g_dwNumMessages;
75extern const TCHAR *g_szMessages[];
76#endif
77
78
79//
80// Valid options for getopt()
81//
82
83#if defined(_WIN32)
9f96fc88 84#define VALID_OPTIONS "c:CdDe:EfhHIM:n:N:P:r:RsSUvX:W:Z:"
5039dede 85#elif defined(_NETWARE)
9fcdfda7 86#define VALID_OPTIONS "c:CDfhM:P:r:vZ:"
5039dede 87#else
9fcdfda7 88#define VALID_OPTIONS "c:CdDfhM:p:P:r:vX:W:Z:"
5039dede
AK
89#endif
90
91
92//
93// Actions
94//
95
96#define ACTION_NONE 0
97#define ACTION_RUN_AGENT 1
98#define ACTION_INSTALL_SERVICE 2
99#define ACTION_REMOVE_SERVICE 3
100#define ACTION_START_SERVICE 4
101#define ACTION_STOP_SERVICE 5
102#define ACTION_CHECK_CONFIG 6
103#define ACTION_INSTALL_EVENT_SOURCE 7
104#define ACTION_REMOVE_EVENT_SOURCE 8
105#define ACTION_CREATE_CONFIG 9
106#define ACTION_HELP 10
9fcdfda7 107#define ACTION_RUN_WATCHDOG 11
5039dede
AK
108
109
110//
111// Global variables
112//
113
114DWORD g_dwFlags = AF_ENABLE_ACTIONS | AF_ENABLE_AUTOLOAD;
115char g_szLogFile[MAX_PATH] = AGENT_DEFAULT_LOG;
116char g_szSharedSecret[MAX_SECRET_LENGTH] = "admin";
117char g_szConfigFile[MAX_PATH] = AGENT_DEFAULT_CONFIG;
118char g_szFileStore[MAX_PATH] = AGENT_DEFAULT_FILE_STORE;
119char g_szPlatformSuffix[MAX_PSUFFIX_LENGTH] = "";
120char g_szConfigServer[MAX_DB_STRING] = "not_set";
121char g_szRegistrar[MAX_DB_STRING] = "not_set";
122char g_szListenAddress[MAX_PATH] = "*";
123WORD g_wListenPort = AGENT_LISTEN_PORT;
124SERVER_INFO g_pServerList[MAX_SERVERS];
125DWORD g_dwServerCount = 0;
126DWORD g_dwExecTimeout = 2000; // External process execution timeout in milliseconds
127DWORD g_dwSNMPTimeout = 3000;
128time_t g_tmAgentStartTime;
129DWORD g_dwStartupDelay = 0;
130DWORD g_dwMaxSessions = 32;
e6c91aac 131Config *g_config;
5039dede
AK
132#ifdef _WIN32
133DWORD g_dwIdleTimeout = 60; // Session idle timeout
134#else
135DWORD g_dwIdleTimeout = 120; // Session idle timeout
136#endif
137
138#if !defined(_WIN32) && !defined(_NETWARE)
139char g_szPidFile[MAX_PATH] = "/var/run/nxagentd.pid";
140#endif
141
142#ifdef _WIN32
143BOOL (__stdcall *imp_GlobalMemoryStatusEx)(LPMEMORYSTATUSEX);
144DWORD (__stdcall *imp_HrLanConnectionNameFromGuidOrPath)(LPWSTR, LPWSTR, LPWSTR, LPDWORD);
145#endif /* _WIN32 */
146
147#ifdef _NETWARE
148int g_nThreadCount = 0;
149#endif
150
151
152//
153// Static variables
154//
155
156static char *m_pszActionList = NULL;
157static char *m_pszShellActionList = NULL;
158static char *m_pszServerList = NULL;
159static char *m_pszControlServerList = NULL;
160static char *m_pszMasterServerList = NULL;
161static char *m_pszSubagentList = NULL;
162static char *m_pszExtParamList = NULL;
163static char *m_pszShExtParamList = NULL;
164static DWORD m_dwEnabledCiphers = 0xFFFF;
165static THREAD m_thSessionWatchdog = INVALID_THREAD_HANDLE;
166static THREAD m_thListener = INVALID_THREAD_HANDLE;
167static THREAD m_thTrapSender = INVALID_THREAD_HANDLE;
168static char m_szProcessToWait[MAX_PATH] = "";
9fcdfda7 169static char m_szDumpDir[MAX_PATH] = "C:\\";
4addc3a3
VK
170static DWORD m_dwMaxLogSize = 16384 * 1024;
171static DWORD m_dwLogHistorySize = 4;
5039dede
AK
172
173#if defined(_WIN32) || defined(_NETWARE)
174static CONDITION m_hCondShutdown = INVALID_CONDITION_HANDLE;
175#endif
176
177#if !defined(_WIN32) && !defined(_NETWARE)
178static pid_t m_pid;
179#endif
180
181
182//
183// Configuration file template
184//
185
186static NX_CFG_TEMPLATE m_cfgTemplate[] =
187{
188 { "Action", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszActionList },
189 { "ActionShellExec", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszShellActionList },
190 { "ControlServers", CT_STRING_LIST, ',', 0, 0, 0, &m_pszControlServerList },
9fcdfda7
VK
191 { "CreateCrashDumps", CT_BOOLEAN, 0, 0, AF_CATCH_EXCEPTIONS, 0, &g_dwFlags },
192 { "DumpDirectory", CT_STRING, 0, 0, MAX_PATH, 0, m_szDumpDir },
5039dede
AK
193 { "EnableActions", CT_BOOLEAN, 0, 0, AF_ENABLE_ACTIONS, 0, &g_dwFlags },
194 { "EnabledCiphers", CT_LONG, 0, 0, 0, 0, &m_dwEnabledCiphers },
195 { "EnableProxy", CT_BOOLEAN, 0, 0, AF_ENABLE_PROXY, 0, &g_dwFlags },
196 { "EnableSNMPProxy", CT_BOOLEAN, 0, 0, AF_ENABLE_SNMP_PROXY, 0, &g_dwFlags },
197 { "EnableSubagentAutoload", CT_BOOLEAN, 0, 0, AF_ENABLE_AUTOLOAD, 0, &g_dwFlags },
9fcdfda7 198 { "EnableWatchdog", CT_BOOLEAN, 0, 0, AF_ENABLE_WATCHDOG, 0, &g_dwFlags },
5039dede
AK
199 { "ExecTimeout", CT_LONG, 0, 0, 0, 0, &g_dwExecTimeout },
200 { "ExternalParameter", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszExtParamList },
201 { "ExternalParameterShellExec", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszShExtParamList },
202 { "FileStore", CT_STRING, 0, 0, MAX_PATH, 0, g_szFileStore },
203 { "InstallationServers", CT_STRING_LIST, ',', 0, 0, 0, &m_pszMasterServerList }, // Old name for MasterServers, deprecated
204 { "ListenAddress", CT_STRING, 0, 0, MAX_PATH, 0, g_szListenAddress },
205 { "ListenPort", CT_WORD, 0, 0, 0, 0, &g_wListenPort },
206 { "LogFile", CT_STRING, 0, 0, MAX_PATH, 0, g_szLogFile },
4addc3a3 207 { "LogHistorySize", CT_LONG, 0, 0, 0, 0, &m_dwLogHistorySize },
5039dede
AK
208 { "LogUnresolvedSymbols", CT_BOOLEAN, 0, 0, AF_LOG_UNRESOLVED_SYMBOLS, 0, &g_dwFlags },
209 { "MasterServers", CT_STRING_LIST, ',', 0, 0, 0, &m_pszMasterServerList },
4addc3a3 210 { "MaxLogSize", CT_LONG, 0, 0, 0, 0, &m_dwMaxLogSize },
5039dede
AK
211 { "MaxSessions", CT_LONG, 0, 0, 0, 0, &g_dwMaxSessions },
212 { "PlatformSuffix", CT_STRING, 0, 0, MAX_PSUFFIX_LENGTH, 0, g_szPlatformSuffix },
213 { "RequireAuthentication", CT_BOOLEAN, 0, 0, AF_REQUIRE_AUTH, 0, &g_dwFlags },
214 { "RequireEncryption", CT_BOOLEAN, 0, 0, AF_REQUIRE_ENCRYPTION, 0, &g_dwFlags },
215 { "Servers", CT_STRING_LIST, ',', 0, 0, 0, &m_pszServerList },
216 { "SessionIdleTimeout", CT_LONG, 0, 0, 0, 0, &g_dwIdleTimeout },
217 { "SharedSecret", CT_STRING, 0, 0, MAX_SECRET_LENGTH, 0, g_szSharedSecret },
218 { "StartupDelay", CT_LONG, 0, 0, 0, 0, &g_dwStartupDelay },
219 { "SubAgent", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszSubagentList },
220 { "TimeOut", CT_IGNORE, 0, 0, 0, 0, NULL },
221 { "WaitForProcess", CT_STRING, 0, 0, MAX_PATH, 0, m_szProcessToWait },
222 { "", CT_END_OF_LIST, 0, 0, 0, 0, NULL }
223};
224
225
226//
227// Help text
228//
229
230static char m_szHelpText[] =
231 "Usage: nxagentd [options]\n"
232 "Where valid options are:\n"
233 " -c <file> : Use configuration file <file> (default " AGENT_DEFAULT_CONFIG ")\n"
234 " -C : Check configuration file and exit\n"
235#ifndef _NETWARE
236 " -d : Run as daemon/service\n"
237#endif
238 " -D : Turn on debug output\n"
9f96fc88
VK
239#ifdef _WIN32
240 " -e <name> : Windows event source name\n"
241#endif
5039dede
AK
242 " -f : Run in foreground\n"
243 " -h : Display help and exit\n"
244#ifdef _WIN32
245 " -H : Hide agent's window when in standalone mode\n"
246 " -I : Install Windows service\n"
247#endif
248 " -M <addr> : Download config from management server <addr>\n"
9f96fc88
VK
249#ifdef _WIN32
250 " -n <name> : Service name\n"
251 " -N <name> : Service display name\n"
252#endif
5039dede
AK
253#if !defined(_WIN32) && !defined(_NETWARE)
254 " -p : Path to pid file (default: /var/run/nxagentd.pid)\n"
255#endif
256 " -P <text> : Set platform suffix to <text>\n"
257 " -r <addr> : Register agent on management server <addr>\n"
258#ifdef _WIN32
259 " -R : Remove Windows service\n"
260 " -s : Start Windows servive\n"
261 " -S : Stop Windows service\n"
262#endif
263 " -v : Display version and exit\n"
264 "\n";
265
266
267#ifdef _WIN32
268
269//
270// Get our own console window handle (an alternative to Microsoft's GetConsoleWindow)
271//
272
273static HWND GetConsoleHWND(void)
274{
275 HWND hWnd;
276 DWORD wpid, cpid;
277
278 cpid = GetCurrentProcessId();
279 while(1)
280 {
281 hWnd = FindWindowEx(NULL, NULL, _T("ConsoleWindowClass"), NULL);
282 if (hWnd == NULL)
283 break;
284
285 GetWindowThreadProcessId(hWnd, &wpid);
286 if (cpid == wpid)
287 break;
288 }
289
290 return hWnd;
291}
292
293
294//
295// Get proc address and write log file
296//
297
298static FARPROC GetProcAddressAndLog(HMODULE hModule, LPCSTR procName)
299{
300 FARPROC ptr;
301
302 ptr = GetProcAddress(hModule, procName);
303 if ((ptr == NULL) && (g_dwFlags & AF_LOG_UNRESOLVED_SYMBOLS))
304 nxlog_write(MSG_NO_FUNCTION, EVENTLOG_WARNING_TYPE, "s", procName);
305 return ptr;
306}
307
308
309//
310// Import symbols
311//
312
313static void ImportSymbols(void)
314{
315 HMODULE hModule;
316
317 // KERNEL32.DLL
318 hModule = GetModuleHandle("KERNEL32.DLL");
319 if (hModule != NULL)
320 {
321 imp_GlobalMemoryStatusEx = (BOOL (__stdcall *)(LPMEMORYSTATUSEX))GetProcAddressAndLog(hModule,"GlobalMemoryStatusEx");
322 }
323 else
324 {
325 nxlog_write(MSG_NO_DLL, EVENTLOG_WARNING_TYPE, "s", "KERNEL32.DLL");
326 }
327
328 // NETMAN.DLL
329 hModule = LoadLibrary("NETMAN.DLL");
330 if (hModule != NULL)
331 {
332 imp_HrLanConnectionNameFromGuidOrPath =
333 (DWORD (__stdcall *)(LPWSTR, LPWSTR, LPWSTR, LPDWORD))GetProcAddressAndLog(hModule,
334 "HrLanConnectionNameFromGuidOrPath");
335 }
336 else
337 {
338 nxlog_write(MSG_NO_DLL, EVENTLOG_WARNING_TYPE, "s", "NETMAN.DLL");
339 }
340}
341
342
343//
344// Shutdown thread (created by H_RestartAgent)
345//
346
347static THREAD_RESULT THREAD_CALL ShutdownThread(void *pArg)
348{
349 Shutdown();
350 ExitProcess(0);
351 return THREAD_OK; // Never reached
352}
353
354#endif /* _WIN32 */
355
356
357//
358// Restart agent
359//
360
361static LONG H_RestartAgent(const TCHAR *pszAction, NETXMS_VALUES_LIST *pArgs, const TCHAR *pData)
362{
363#ifdef _NETWARE
364 return ERR_NOT_IMPLEMENTED;
365#else
366 TCHAR szCmdLine[4096], szPlatformSuffixOption[MAX_PSUFFIX_LENGTH + 16];
367#ifdef _WIN32
368 TCHAR szExecName[MAX_PATH];
369 DWORD dwResult;
370 STARTUPINFO si;
371 PROCESS_INFORMATION pi;
372
373 GetModuleFileName(GetModuleHandle(NULL), szExecName, MAX_PATH);
374#else
375 TCHAR szExecName[MAX_PATH] = PREFIX _T("/bin/nxagentd");
376#endif
377
378 if (g_szPlatformSuffix[0] != 0)
379 {
380 _sntprintf(szPlatformSuffixOption, MAX_PSUFFIX_LENGTH + 16, _T("-P \"%s\" "), g_szPlatformSuffix);
381 }
382 else
383 {
384 szPlatformSuffixOption[0] = 0;
385 }
386
387#ifdef _WIN32
388 _sntprintf(szCmdLine, 4096, _T("\"%s\" -c \"%s\" %s%s%s%s%s%s%s-X %u"), szExecName,
389 g_szConfigFile, (g_dwFlags & AF_DAEMON) ? _T("-d ") : _T(""),
390 (g_dwFlags & AF_HIDE_WINDOW) ? _T("-H ") : _T(""),
391 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T("-M ") : _T(""),
392 (g_dwFlags & AF_CENTRAL_CONFIG) ? g_szConfigServer : _T(""),
393 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T(" ") : _T(""),
394 (g_dwFlags & AF_DEBUG) ? _T("-D ") : _T(""),
395 szPlatformSuffixOption,
396 (g_dwFlags & AF_DAEMON) ? 0 : GetCurrentProcessId());
397 DebugPrintf(INVALID_INDEX, _T("Restarting agent with command line '%s'"), szCmdLine);
398
399
400 // Fill in process startup info structure
401 memset(&si, 0, sizeof(STARTUPINFO));
402 si.cb = sizeof(STARTUPINFO);
403
404 // Create new process
405 if (!CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE,
406 (g_dwFlags & AF_DAEMON) ? (CREATE_NO_WINDOW | DETACHED_PROCESS) : (CREATE_NEW_CONSOLE),
407 NULL, NULL, &si, &pi))
408 {
409 nxlog_write(MSG_CREATE_PROCESS_FAILED, EVENTLOG_ERROR_TYPE, "se", szCmdLine, GetLastError());
410 dwResult = ERR_EXEC_FAILED;
411 }
412 else
413 {
414 // Close all handles
415 CloseHandle(pi.hThread);
416 CloseHandle(pi.hProcess);
417 dwResult = ERR_SUCCESS;
418 }
419 if ((dwResult == ERR_SUCCESS) && (!(g_dwFlags & AF_DAEMON)))
420 {
421 if (g_dwFlags & AF_HIDE_WINDOW)
422 {
423 ConditionSet(m_hCondShutdown);
424 }
425 else
426 {
427 ThreadCreate(ShutdownThread, 0, NULL);
428 }
429 }
430 return dwResult;
431#else
432 _sntprintf(szCmdLine, 4096, _T("\"%s\" -c \"%s\" %s%s%s%s%s%s-X %lu"), szExecName,
433 g_szConfigFile, (g_dwFlags & AF_DAEMON) ? _T("-d ") : _T(""),
434 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T("-M ") : _T(""),
435 (g_dwFlags & AF_CENTRAL_CONFIG) ? g_szConfigServer : _T(""),
436 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T(" ") : _T(""),
437 (g_dwFlags & AF_DEBUG) ? _T("-D ") : _T(""),
438 szPlatformSuffixOption,
439 (unsigned long)m_pid);
9fcdfda7 440 return ExecuteCommand(szCmdLine, NULL, NULL);
5039dede
AK
441#endif
442#endif /* _NETWARE */
443}
444
445
446//
447// This function writes message from subagent to agent's log
448//
449
450static void WriteSubAgentMsg(int iLevel, TCHAR *pszMsg)
451{
452 if (iLevel == EVENTLOG_DEBUG_TYPE)
453 {
454 DebugPrintf(INVALID_INDEX, _T("%s"), pszMsg);
455 }
456 else
457 {
458 nxlog_write(MSG_SUBAGENT_MSG, iLevel, "s", pszMsg);
459 }
460}
461
462
463//
464// Signal handler for UNIX platforms
465//
466
467#if !defined(_WIN32) && !defined(_NETWARE)
468
469static THREAD_RESULT THREAD_CALL SignalHandler(void *pArg)
470{
471 sigset_t signals;
472 int nSignal;
473
474 sigemptyset(&signals);
475 sigaddset(&signals, SIGTERM);
476 sigaddset(&signals, SIGINT);
477 sigaddset(&signals, SIGPIPE);
478 sigaddset(&signals, SIGSEGV);
479 sigaddset(&signals, SIGHUP);
480 sigaddset(&signals, SIGUSR1);
481 sigaddset(&signals, SIGUSR2);
482
483 sigprocmask(SIG_BLOCK, &signals, NULL);
484
485 while(1)
486 {
487 if (sigwait(&signals, &nSignal) == 0)
488 {
489 switch(nSignal)
490 {
491 case SIGTERM:
492 case SIGINT:
493 goto stop_handler;
494 case SIGSEGV:
495 abort();
496 break;
497 default:
498 break;
499 }
500 }
501 else
502 {
503 ThreadSleepMs(100);
504 }
505 }
506
507stop_handler:
508 sigprocmask(SIG_UNBLOCK, &signals, NULL);
509 return THREAD_OK;
510}
511
512#endif
513
514
515//
516// Load subagent for Windows NT or Windows 9x or platform subagent on UNIX
517//
518
519#ifdef _WIN32
520
521void LoadWindowsSubagent(void)
522{
523 OSVERSIONINFO ver;
524
525 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
526 if (GetVersionEx(&ver))
527 {
528 switch(ver.dwPlatformId)
529 {
530 case VER_PLATFORM_WIN32_WINDOWS: // Windows 9x
531 LoadSubAgent("WIN9X.NSM");
532 break;
533 case VER_PLATFORM_WIN32_NT: // Windows NT or higher
534 LoadSubAgent("WINNT.NSM");
535 break;
536 default:
537 break;
538 }
539 }
540 else
541 {
542 nxlog_write(MSG_GETVERSION_FAILED, EVENTLOG_WARNING_TYPE, "e", GetLastError());
543 }
544}
545
546#else
547
548void LoadPlatformSubagent(void)
549{
550#if defined(_NETWARE)
551 LoadSubAgent("NETWARE.NSM");
552#elif HAVE_SYS_UTSNAME_H && !defined(_STATIC_AGENT)
553 struct utsname un;
554 char szName[MAX_PATH];
555 int i;
556
557 if (uname(&un) != -1)
558 {
559 // Convert system name to lowercase
560 for(i = 0; un.sysname[i] != 0; i++)
561 un.sysname[i] = tolower(un.sysname[i]);
562 if (!strcmp(un.sysname, "hp-ux"))
563 strcpy(un.sysname, "hpux");
564 sprintf(szName, LIBDIR "/libnsm_%s" SHL_SUFFIX, un.sysname);
565 LoadSubAgent(szName);
566 }
567#endif
568}
569
570#endif
571
572
573//
574// Initialization routine
575//
576
577BOOL Initialize(void)
578{
579 char *pItem, *pEnd;
580#ifdef _NETWARE
581 char szLoadPath[1024], szSearchPath[1024];
582#endif
583
584 // Open log file
4addc3a3
VK
585 if (!(g_dwFlags & AF_USE_SYSLOG))
586 {
587 if (!nxlog_set_rotation_policy((int)m_dwMaxLogSize, (int)m_dwLogHistorySize))
588 if (!(g_dwFlags & AF_DAEMON))
589 printf("WARNING: cannot set log rotation policy; using default values\n");
590 }
9fcdfda7
VK
591 if (!nxlog_open((g_dwFlags & AF_USE_SYSLOG) ? NXAGENTD_SYSLOG_NAME : g_szLogFile,
592 ((g_dwFlags & AF_USE_SYSLOG) ? NXLOG_USE_SYSLOG : 0) |
593 ((g_dwFlags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
594 _T("NXAGENTD.EXE"),
5039dede 595#ifdef _WIN32
9fcdfda7 596 0, NULL))
5039dede 597#else
9fcdfda7 598 g_dwNumMessages, g_szMessages))
5039dede 599#endif
9fcdfda7
VK
600 {
601 fprintf(stderr, "FATAL ERROR: Cannot open log file\n");
602 return FALSE;
603 }
604 DebugPrintf(INVALID_INDEX, "Log file opened");
5039dede
AK
605
606#ifdef _WIN32
607 WSADATA wsaData;
608 OSVERSIONINFO ver;
609
610 if (WSAStartup(2, &wsaData) != 0)
611 {
612 nxlog_write(MSG_WSASTARTUP_FAILED, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError());
613 return FALSE;
614 }
615
616 // Set NT4 flag
617 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
618 if (GetVersionEx(&ver))
619 {
620 if ((ver.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
621 (ver.dwMajorVersion <= 4))
622 {
623 g_dwFlags |= AF_RUNNING_ON_NT4;
624 DebugPrintf(INVALID_INDEX, "Running on Windows NT 4.0");
625 }
626 }
627#endif
628
629 // Add NLM load path to search list
630#ifdef _NETWARE
631 if (getnlmloadpath(szLoadPath) != NULL)
632 {
633 int i, nIsDOS;
634 BOOL bExist = FALSE;
635
636 for(i = 0; ; i++)
637 {
638 if (GetSearchPathElement(i, &nIsDOS, szSearchPath) != 0)
639 break;
640 if (strlen(szLoadPath) == szSearchPath[0])
641 if (!strncasecmp(&szSearchPath[1], szLoadPath, szSearchPath[0]))
642 {
643 bExist = TRUE;
644 break;
645 }
646 }
647 if (!bExist)
648 InsertSearchPath(getnetwarelogger(), 0, szLoadPath);
649 }
650#endif
651
652 // Initialize API for subagents
653 InitSubAgentsLogger(WriteSubAgentMsg);
654 InitSubAgentsTrapSender(SendTrap, SendTrap);
655 DebugPrintf(INVALID_INDEX, "Subagent API initialized");
656
657 // Initialize cryptografy
658 if (!InitCryptoLib(m_dwEnabledCiphers))
659 {
660 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError());
661 return FALSE;
662 }
663
664 // Initialize built-in parameters
665 if (!InitParameterList())
666 return FALSE;
667
668#ifdef _WIN32
669 // Dynamically import functions that may not be presented in all Windows versions
670 ImportSymbols();
671#endif
672
673 // Parse server list
674 if (m_pszServerList != NULL)
675 {
e6c91aac 676 for(pItem = pEnd = m_pszServerList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
677 {
678 pEnd = strchr(pItem, ',');
679 if (pEnd != NULL)
680 *pEnd = 0;
681 StrStrip(pItem);
682 g_pServerList[g_dwServerCount].dwIpAddr = ResolveHostName(pItem);
683 if ((g_pServerList[g_dwServerCount].dwIpAddr == INADDR_NONE) ||
684 (g_pServerList[g_dwServerCount].dwIpAddr == INADDR_ANY))
685 {
686 if (!(g_dwFlags & AF_DAEMON))
687 printf("Invalid server address '%s'\n", pItem);
688 }
689 else
690 {
691 g_pServerList[g_dwServerCount].bMasterServer = FALSE;
692 g_pServerList[g_dwServerCount].bControlServer = FALSE;
693 g_dwServerCount++;
694 }
695 }
696 free(m_pszServerList);
697 }
698
699 // Parse master server list
700 if (m_pszMasterServerList != NULL)
701 {
702 DWORD i, dwAddr;
703
e6c91aac 704 for(pItem = pEnd = m_pszMasterServerList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
705 {
706 pEnd = strchr(pItem, ',');
707 if (pEnd != NULL)
708 *pEnd = 0;
709 StrStrip(pItem);
710
711 dwAddr = ResolveHostName(pItem);
712 if ((dwAddr == INADDR_NONE) ||
713 (dwAddr == INADDR_ANY))
714 {
715 if (!(g_dwFlags & AF_DAEMON))
716 printf("Invalid server address '%s'\n", pItem);
717 }
718 else
719 {
720 for(i = 0; i < g_dwServerCount; i++)
721 if (g_pServerList[i].dwIpAddr == dwAddr)
722 break;
723
724 if (i == g_dwServerCount)
725 {
726 g_pServerList[g_dwServerCount].dwIpAddr = dwAddr;
727 g_pServerList[g_dwServerCount].bMasterServer = TRUE;
728 g_pServerList[g_dwServerCount].bControlServer = TRUE;
729 g_dwServerCount++;
730 }
731 else
732 {
733 g_pServerList[i].bMasterServer = TRUE;
734 g_pServerList[i].bControlServer = TRUE;
735 }
736 }
737 }
738 free(m_pszMasterServerList);
739 }
740
741 // Parse control server list
742 if (m_pszControlServerList != NULL)
743 {
744 DWORD i, dwAddr;
745
e6c91aac 746 for(pItem = pEnd = m_pszControlServerList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
747 {
748 pEnd = strchr(pItem, ',');
749 if (pEnd != NULL)
750 *pEnd = 0;
751 StrStrip(pItem);
752
753 dwAddr = ResolveHostName(pItem);
754 if ((dwAddr == INADDR_NONE) ||
755 (dwAddr == INADDR_ANY))
756 {
757 if (!(g_dwFlags & AF_DAEMON))
758 printf("Invalid server address '%s'\n", pItem);
759 }
760 else
761 {
762 for(i = 0; i < g_dwServerCount; i++)
763 if (g_pServerList[i].dwIpAddr == dwAddr)
764 break;
765
766 if (i == g_dwServerCount)
767 {
768 g_pServerList[g_dwServerCount].dwIpAddr = dwAddr;
769 g_pServerList[g_dwServerCount].bMasterServer = FALSE;
770 g_pServerList[g_dwServerCount].bControlServer = TRUE;
771 g_dwServerCount++;
772 }
773 else
774 {
775 g_pServerList[i].bControlServer = TRUE;
776 }
777 }
778 }
779 free(m_pszControlServerList);
780 }
781
782 // Add built-in actions
783 AddAction("Agent.Restart", AGENT_ACTION_SUBAGENT, NULL, H_RestartAgent, "CORE", "Restart agent");
784
785 // Load platform subagents
786#if !defined(_WIN32) && !defined(_NETWARE)
787 InitStaticSubagents();
788#endif
789 if (g_dwFlags & AF_ENABLE_AUTOLOAD)
790 {
791#ifdef _WIN32
792 LoadWindowsSubagent();
793#else
794 LoadPlatformSubagent();
795#endif
796 }
797
798 // Wait for external process if requested
799 if (m_szProcessToWait[0] != 0)
800 {
801 DebugPrintf(INVALID_INDEX, "Waiting for process %s", m_szProcessToWait);
802 if (!WaitForProcess(m_szProcessToWait))
803 nxlog_write(MSG_WAITFORPROCESS_FAILED, EVENTLOG_ERROR_TYPE, "s", m_szProcessToWait);
804 }
805
806 // Load other subagents
807 if (m_pszSubagentList != NULL)
808 {
e6c91aac 809 for(pItem = pEnd = m_pszSubagentList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
810 {
811 pEnd = strchr(pItem, '\n');
812 if (pEnd != NULL)
813 *pEnd = 0;
814 StrStrip(pItem);
815 LoadSubAgent(pItem);
816 }
817 free(m_pszSubagentList);
818 }
819
820 // Parse action list
821 if (m_pszActionList != NULL)
822 {
e6c91aac 823 for(pItem = pEnd = m_pszActionList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
824 {
825 pEnd = strchr(pItem, '\n');
826 if (pEnd != NULL)
827 *pEnd = 0;
828 StrStrip(pItem);
829 if (!AddActionFromConfig(pItem, FALSE))
830 nxlog_write(MSG_ADD_ACTION_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
831 }
832 free(m_pszActionList);
833 }
834 if (m_pszShellActionList != NULL)
835 {
e6c91aac 836 for(pItem = pEnd = m_pszShellActionList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
837 {
838 pEnd = strchr(pItem, '\n');
839
840 if (pEnd != NULL)
841 *pEnd = 0;
842 StrStrip(pItem);
843 if (!AddActionFromConfig(pItem, TRUE))
844 nxlog_write(MSG_ADD_ACTION_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
845 }
846 free(m_pszShellActionList);
847 }
848
849 // Parse external parameters list
850 if (m_pszExtParamList != NULL)
851 {
e6c91aac 852 for(pItem = pEnd = m_pszExtParamList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
853 {
854 pEnd = strchr(pItem, '\n');
855 if (pEnd != NULL)
856 *pEnd = 0;
857 StrStrip(pItem);
858 if (!AddExternalParameter(pItem, FALSE))
859 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
860 }
861 free(m_pszExtParamList);
862 }
863 if (m_pszShExtParamList != NULL)
864 {
e6c91aac 865 for(pItem = pEnd = m_pszShExtParamList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
866 {
867 pEnd = strchr(pItem, '\n');
868 if (pEnd != NULL)
869 *pEnd = 0;
870 StrStrip(pItem);
871 if (!AddExternalParameter(pItem, TRUE))
872 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
873 }
874 free(m_pszShExtParamList);
875 }
876
877 ThreadSleep(1);
878
879 // If StartupDelay is greater than zero, then wait
880 if (g_dwStartupDelay > 0)
881 {
882 if (g_dwFlags & AF_DAEMON)
883 {
884 ThreadSleep(g_dwStartupDelay);
885 }
886 else
887 {
888 DWORD i;
889
890 printf("XXXXXX%*s]\rWAIT [", g_dwStartupDelay, " ");
891 fflush(stdout);
892 for(i = 0; i < g_dwStartupDelay; i++)
893 {
894 ThreadSleep(1);
895 putc('.', stdout);
896 fflush(stdout);
897 }
898 printf("\n");
899 }
900 }
901
902 // Agent start time
903 g_tmAgentStartTime = time(NULL);
904
905 // Start network listener and session watchdog
906 m_thListener = ThreadCreateEx(ListenerThread, 0, NULL);
907 m_thSessionWatchdog = ThreadCreateEx(SessionWatchdog, 0, NULL);
908 m_thTrapSender = ThreadCreateEx(TrapSender, 0, NULL);
909
910#if defined(_WIN32) || defined(_NETWARE)
911 m_hCondShutdown = ConditionCreate(TRUE);
912#endif
913 ThreadSleep(1);
914
9fcdfda7
VK
915 // Start watchdog process
916 if (g_dwFlags & AF_ENABLE_WATCHDOG)
917 StartWatchdog();
918
5039dede
AK
919 return TRUE;
920}
921
922
923//
924// Shutdown routine
925//
926
927void Shutdown(void)
928{
9fcdfda7
VK
929 if (g_dwFlags & AF_ENABLE_WATCHDOG)
930 StopWatchdog();
931
5039dede
AK
932 // Set shutdowm flag
933 g_dwFlags |= AF_SHUTDOWN;
934 ShutdownTrapSender();
935 ThreadJoin(m_thSessionWatchdog);
936 ThreadJoin(m_thListener);
937 ThreadJoin(m_thTrapSender);
938
939 UnloadAllSubAgents();
940 nxlog_write(MSG_AGENT_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
941 nxlog_close();
942
943 // Notify main thread about shutdown
944#ifdef _WIN32
945 ConditionSet(m_hCondShutdown);
946#endif
947
948 // Remove PID file
949#if !defined(_WIN32) && !defined(_NETWARE)
950 remove(g_szPidFile);
951#endif
952}
953
954
955//
956// Common Main()
957//
958
959void Main(void)
960{
961 nxlog_write(MSG_AGENT_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
962
963 if (g_dwFlags & AF_DAEMON)
964 {
965#if defined(_WIN32) || defined(_NETWARE)
966 ConditionWait(m_hCondShutdown, INFINITE);
967#else
968 StartMainLoop(SignalHandler, NULL);
969#endif
970 }
971 else
972 {
973#if defined(_WIN32)
974 if (g_dwFlags & AF_HIDE_WINDOW)
975 {
976 HWND hWnd;
977
978 hWnd = GetConsoleHWND();
979 if (hWnd != NULL)
980 ShowWindow(hWnd, SW_HIDE);
981 ConditionWait(m_hCondShutdown, INFINITE);
982 ThreadSleep(1);
983 }
984 else
985 {
986 printf("Agent running. Press ESC to shutdown.\n");
987 while(1)
988 {
3973f74b 989 if (_getch() == 27)
5039dede
AK
990 break;
991 }
992 printf("Agent shutting down...\n");
993 Shutdown();
994 }
995#elif defined(_NETWARE)
996 printf("Agent running. Type UNLOAD NXAGENTD on the system console for shutdown.\n");
997 ConditionWait(m_hCondShutdown, INFINITE);
998#else
999 printf("Agent running. Press Ctrl+C to shutdown.\n");
1000 StartMainLoop(SignalHandler, NULL);
1001 printf("\nStopping agent...\n");
1002#endif
1003 }
1004}
1005
1006
1007//
1008// Do necessary actions on agent restart
1009//
1010
1011static void DoRestartActions(DWORD dwOldPID)
1012{
1013#if defined(_WIN32)
1014 if (dwOldPID == 0)
1015 {
1016 // Service
1017 StopAgentService();
1018 WaitForService(SERVICE_STOPPED);
1019 StartAgentService();
1020 ExitProcess(0);
1021 }
1022 else
1023 {
1024 HANDLE hProcess;
1025
1026 hProcess = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, dwOldPID);
1027 if (hProcess != NULL)
1028 {
1029 if (WaitForSingleObject(hProcess, 60000) == WAIT_TIMEOUT)
1030 {
1031 TerminateProcess(hProcess, 0);
1032 }
1033 CloseHandle(hProcess);
1034 }
1035 }
1036#elif defined(_NETWARE)
1037 /* TODO: implement restart for NetWare */
1038#else
1039 int i;
1040
1041 kill(dwOldPID, SIGTERM);
1042 for(i = 0; i < 30; i++)
1043 {
1044 sleep(2);
1045 if (kill(dwOldPID, SIGCONT) == -1)
1046 break;
1047 }
1048
1049 // Kill previous instance of agent if it's still running
1050 if (i == 30)
1051 kill(dwOldPID, SIGKILL);
1052#endif
1053}
1054
1055
1056//
1057// NetWare exit handler
1058//
1059
1060#ifdef _NETWARE
1061
1062static void ExitHandler(int nSig)
1063{
1064 printf("\n*** Unloading NetXMS agent ***\n");
1065 ConditionSet(m_hCondShutdown);
1066 while(g_nThreadCount > 0)
1067 pthread_yield();
1068}
1069
1070#endif
1071
1072
1073//
1074// Create configuration file
1075//
1076
1077static int CreateConfig(TCHAR *pszServer, TCHAR *pszLogFile, TCHAR *pszFileStore,
1078 int iNumSubAgents, TCHAR **ppszSubAgentList)
1079{
1080 FILE *fp;
1081 time_t currTime;
1082 int i;
1083
1084 if (_taccess(g_szConfigFile, 0) == 0)
1085 return 0; // File already exist, we shouldn't overwrite it
1086
1087 fp = _tfopen(g_szConfigFile, _T("w"));
1088 if (fp != NULL)
1089 {
1090 currTime = time(NULL);
1091 _ftprintf(fp, _T("#\n# NetXMS agent configuration file\n# Created by agent installer at %s#\n\n"),
1092 _tctime(&currTime));
1093 _ftprintf(fp, _T("MasterServers = %s\nLogFile = %s\nFileStore = %s\n"),
1094 pszServer, pszLogFile, pszFileStore);
1095 for(i = 0; i < iNumSubAgents; i++)
1096 _ftprintf(fp, _T("SubAgent = %s\n"), ppszSubAgentList[i]);
1097 fclose(fp);
1098 }
1099 return (fp != NULL) ? 0 : 2;
1100}
1101
1102
e6c91aac
VK
1103//
1104// Init config
1105//
1106
1107static void InitConfig()
1108{
1109 g_config = new Config();
1110}
1111
1112
5039dede
AK
1113//
1114// Startup
1115//
1116
1117int main(int argc, char *argv[])
1118{
1119 int ch, iExitCode = 0, iAction = ACTION_RUN_AGENT;
1120 BOOL bRestart = FALSE;
9fcdfda7 1121 DWORD dwOldPID, dwMainPID;
5039dede
AK
1122#ifdef _WIN32
1123 char szModuleName[MAX_PATH];
1124#endif
1125
1126 InitThreadLibrary();
9fcdfda7
VK
1127
1128#ifdef NETXMS_MEMORY_DEBUG
1129 InitMemoryDebugger();
1130#endif
5039dede
AK
1131
1132#ifdef _NETWARE
1133 g_nThreadCount++;
1134 setscreenmode(SCR_AUTOCLOSE_ON_EXIT | SCR_COLOR_ATTRS);
1135#endif
1136
1137 // Set locale to C. It shouldn't be needed, according to
1138 // documentation, but I've seen the cases when agent formats
1139 // floating point numbers by sprintf inserting comma in place
1140 // of a dot, as set by system's regional settings.
1141#ifdef _WIN32
1142 setlocale(LC_ALL, "C");
1143#endif
1144
1145 // Parse command line
1146 if (argc == 1)
1147 iAction = ACTION_HELP;
1148 opterr = 1;
1149 while((ch = getopt(argc, argv, VALID_OPTIONS)) != -1)
1150 {
1151 switch(ch)
1152 {
1153 case 'h': // Display help and exit
1154 iAction = ACTION_HELP;
1155 break;
1156 case 'd': // Run as daemon
1157 g_dwFlags |= AF_DAEMON;
1158 break;
1159 case 'f': // Run in foreground
1160 g_dwFlags &= ~AF_DAEMON;
1161 break;
1162 case 'D': // Turn on debug output
1163 g_dwFlags |= AF_DEBUG;
1164 break;
1165 case 'c': // Configuration file
1166 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
1167 break;
1168#if !defined(_WIN32) && !defined(_NETWARE)
1169 case 'p': // PID file
1170 nx_strncpy(g_szPidFile, optarg, MAX_PATH);
1171 break;
1172#endif
1173 case 'C': // Configuration check only
1174 iAction = ACTION_CHECK_CONFIG;
1175 break;
1176 case 'v': // Print version and exit
1177 printf("NetXMS Core Agent Version " AGENT_VERSION_STRING "\n");
1178 iAction = ACTION_NONE;
1179 break;
1180 case 'M':
1181 g_dwFlags |= AF_CENTRAL_CONFIG;
1182 nx_strncpy(g_szConfigServer, optarg, MAX_DB_STRING);
1183 break;
1184 case 'r':
1185 g_dwFlags |= AF_REGISTER;
1186 nx_strncpy(g_szRegistrar, optarg, MAX_DB_STRING);
1187 break;
1188 case 'P': // Platform suffix
1189 nx_strncpy(g_szPlatformSuffix, optarg, MAX_PSUFFIX_LENGTH);
1190 break;
1191 case 'X': // Agent is being restarted
1192 bRestart = TRUE;
1193 dwOldPID = strtoul(optarg, NULL, 10);
1194 break;
9fcdfda7
VK
1195 case 'W': // Watchdog process
1196 iAction = ACTION_RUN_WATCHDOG;
1197 dwMainPID = strtoul(optarg, NULL, 10);
1198 break;
5039dede
AK
1199 case 'Z': // Create configuration file
1200 iAction = ACTION_CREATE_CONFIG;
1201 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
1202 break;
1203#ifdef _WIN32
1204 case 'H': // Hide window
1205 g_dwFlags |= AF_HIDE_WINDOW;
1206 break;
1207 case 'I': // Install Windows service
1208 iAction = ACTION_INSTALL_SERVICE;
1209 break;
1210 case 'R': // Remove Windows service
1211 iAction = ACTION_REMOVE_SERVICE;
1212 break;
1213 case 's': // Start Windows service
1214 iAction = ACTION_START_SERVICE;
1215 break;
1216 case 'S': // Stop Windows service
1217 iAction = ACTION_STOP_SERVICE;
1218 break;
1219 case 'E': // Install Windows event source
1220 iAction = ACTION_INSTALL_EVENT_SOURCE;
1221 break;
1222 case 'U': // Remove Windows event source
1223 iAction = ACTION_REMOVE_EVENT_SOURCE;
1224 break;
9f96fc88
VK
1225 case 'e': // Event source name
1226 nx_strncpy(g_windowsEventSourceName, optarg, MAX_PATH);
1227 break;
1228 case 'n': // Service name
1229 nx_strncpy(g_windowsServiceName, optarg, MAX_PATH);
1230 break;
1231 case 'N': // Service display name
1232 nx_strncpy(g_windowsServiceDisplayName, optarg, MAX_PATH);
1233 break;
5039dede
AK
1234#endif
1235 case '?':
1236 iAction = ACTION_HELP;
1237 iExitCode = 1;
1238 break;
1239 default:
1240 break;
1241 }
1242 }
1243
1244#if !defined(_WIN32) && !defined(_NETWARE)
1245 if (!_tcscmp(g_szConfigFile, _T("{search}")))
1246 {
1247 if (access(PREFIX "/etc/nxagentd.conf", 4) == 0)
1248 {
1249 _tcscpy(g_szConfigFile, PREFIX "/etc/nxagentd.conf");
1250 }
1251 else if (access("/usr/etc/nxagentd.conf", 4) == 0)
1252 {
1253 _tcscpy(g_szConfigFile, "/usr/etc/nxagentd.conf");
1254 }
1255 else
1256 {
1257 _tcscpy(g_szConfigFile, "/etc/nxagentd.conf");
1258 }
1259 }
1260#endif
1261
1262 if (bRestart)
1263 DoRestartActions(dwOldPID);
1264
e6c91aac
VK
1265 InitConfig();
1266
5039dede
AK
1267 // Do requested action
1268 switch(iAction)
1269 {
1270 case ACTION_RUN_AGENT:
1271 // Set default value for session idle timeout based on
1272 // connect() timeout, if possible
1273#if HAVE_SYSCTLBYNAME && !defined(_IPSO)
1274 {
1275 LONG nVal;
1276 size_t nSize;
1277
1278 nSize = sizeof(nVal);
1279 if (sysctlbyname("net.inet.tcp.keepinit", &nVal, &nSize, NULL, 0) == 0)
1280 {
1281 g_dwIdleTimeout = nVal / 1000 + 15;
1282 }
1283 }
1284#endif
1285
1286 if (g_dwFlags & AF_CENTRAL_CONFIG)
1287 {
1288 if (g_dwFlags & AF_DEBUG)
1289 printf("Downloading configuration from %s...\n", g_szConfigServer);
1290 if (DownloadConfig(g_szConfigServer))
1291 {
1292 if (g_dwFlags & AF_DEBUG)
1293 printf("Configuration downloaded successfully\n");
1294 }
1295 else
1296 {
1297 if (g_dwFlags & AF_DEBUG)
1298 printf("Configuration download failed\n");
1299 }
1300 }
1301
97a92859 1302 if (g_config->loadConfig(g_szConfigFile, _T("agent")) && g_config->parseTemplate(_T("agent"), m_cfgTemplate))
e6c91aac 1303 {
9fcdfda7
VK
1304 // Set exception handler
1305#ifdef _WIN32
1306 if (g_dwFlags & AF_CATCH_EXCEPTIONS)
1307 SetExceptionHandler(SEHServiceExceptionHandler, SEHServiceExceptionDataWriter, m_szDumpDir,
1308 "nxagentd", MSG_EXCEPTION, !(g_dwFlags & AF_DAEMON));
1309 __try {
1310#endif
5039dede
AK
1311 if ((!stricmp(g_szLogFile, "{syslog}")) ||
1312 (!stricmp(g_szLogFile, "{eventlog}")))
1313 g_dwFlags |= AF_USE_SYSLOG;
1314
1315#ifdef _WIN32
1316 if (g_dwFlags & AF_DAEMON)
1317 {
1318 InitService();
1319 }
1320 else
1321 {
1322 if (Initialize())
1323 {
1324 Main();
1325 }
1326 else
1327 {
1328 ConsolePrintf("Agent initialization failed\n");
1329 nxlog_close();
1330 iExitCode = 3;
1331 }
1332 }
1333#else /* _WIN32 */
1334#ifndef _NETWARE
1335 if (g_dwFlags & AF_DAEMON)
1336 if (daemon(0, 0) == -1)
1337 {
1338 perror("Unable to setup itself as a daemon");
1339 iExitCode = 4;
1340 }
1341#endif
1342 if (iExitCode == 0)
1343 {
1344#ifndef _NETWARE
1345 m_pid = getpid();
1346#endif
1347 if (Initialize())
1348 {
1349#ifdef _NETWARE
1350 signal(SIGTERM, ExitHandler);
1351#else
1352 FILE *fp;
1353
1354 // Write PID file
1355 fp = fopen(g_szPidFile, "w");
1356 if (fp != NULL)
1357 {
1358 fprintf(fp, "%d", m_pid);
1359 fclose(fp);
1360 }
1361#endif
1362 Main();
1363 Shutdown();
1364 }
1365 else
1366 {
1367 ConsolePrintf("Agent initialization failed\n");
1368 nxlog_close();
1369 iExitCode = 3;
1370 }
1371 }
1372#endif /* _WIN32 */
1373
1374#if defined(_WIN32) || defined(_NETWARE)
1375 if (m_hCondShutdown != INVALID_CONDITION_HANDLE)
1376 ConditionDestroy(m_hCondShutdown);
9fcdfda7
VK
1377#endif
1378#ifdef _WIN32
1379 LIBNETXMS_EXCEPTION_HANDLER
5039dede
AK
1380#endif
1381 }
1382 else
1383 {
1384 ConsolePrintf("Error loading configuration file\n");
1385 iExitCode = 2;
1386 }
1387 break;
1388 case ACTION_CHECK_CONFIG:
97a92859 1389 if (!g_config->loadIniConfig(g_szConfigFile, _T("agent")) || !g_config->parseTemplate(_T("agent"), m_cfgTemplate))
5039dede
AK
1390 {
1391 ConsolePrintf("Configuration file check failed\n");
1392 iExitCode = 2;
1393 }
1394 break;
9fcdfda7
VK
1395 case ACTION_RUN_WATCHDOG:
1396 iExitCode = WatchdogMain(dwMainPID);
1397 break;
5039dede
AK
1398 case ACTION_CREATE_CONFIG:
1399 iExitCode = CreateConfig(CHECK_NULL(argv[optind]), CHECK_NULL(argv[optind + 1]),
1400 CHECK_NULL(argv[optind + 2]), argc - optind - 3,
1401 &argv[optind + 3]);
1402 break;
1403#ifdef _WIN32
1404 case ACTION_INSTALL_SERVICE:
1405 GetModuleFileName(GetModuleHandle(NULL), szModuleName, MAX_PATH);
1406 InstallService(szModuleName, g_szConfigFile);
1407 break;
1408 case ACTION_REMOVE_SERVICE:
1409 RemoveService();
1410 break;
1411 case ACTION_INSTALL_EVENT_SOURCE:
1412 GetModuleFileName(GetModuleHandle(NULL), szModuleName, MAX_PATH);
1413 InstallEventSource(szModuleName);
1414 break;
1415 case ACTION_REMOVE_EVENT_SOURCE:
1416 RemoveEventSource();
1417 break;
1418 case ACTION_START_SERVICE:
1419 StartAgentService();
1420 break;
1421 case ACTION_STOP_SERVICE:
1422 StopAgentService();
1423 break;
1424#endif
1425 case ACTION_HELP:
9fcdfda7 1426 fputs(m_szHelpText, stdout);
5039dede
AK
1427 break;
1428 default:
1429 break;
1430 }
1431
1432#ifdef _NETWARE
1433 if ((iExitCode != 0) || (iAction == ACTION_NONE) ||
1434 (iAction == ACTION_CHECK_CONFIG))
1435 setscreenmode(SCR_NO_MODE);
1436 g_nThreadCount--;
1437#endif
1438
1439 return iExitCode;
1440}