Build process fixed for clean checkout
[public/netxms.git] / src / agent / core / nxagentd.cpp
CommitLineData
cc022855 1/*
5039dede 2** NetXMS multiplatform core agent
c1099678 3** Copyright (C) 2003-2014 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**
f0c1d2a4
AK
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
5039dede
AK
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"
b34606f7 24#include <nxdbapi.h>
5039dede
AK
25
26#if defined(_WIN32)
27#include <conio.h>
5039dede
AK
28#else
29#include <signal.h>
30#include <sys/wait.h>
31#endif
32
c1099678
VK
33#if HAVE_LOCALE_H
34#include <locale.h>
35#endif
36
5039dede
AK
37#if HAVE_SYS_UTSNAME_H
38#include <sys/utsname.h>
39#endif
40
41#if HAVE_SYS_SYSCTL_H
42#include <sys/sysctl.h>
43#endif
44
45
46//
47// Externals
48//
49
50THREAD_RESULT THREAD_CALL ListenerThread(void *);
51THREAD_RESULT THREAD_CALL SessionWatchdog(void *);
52THREAD_RESULT THREAD_CALL TrapSender(void *);
0df58041 53THREAD_RESULT THREAD_CALL MasterAgentListener(void *arg);
5039dede
AK
54
55void ShutdownTrapSender();
56
9fcdfda7
VK
57void StartWatchdog();
58void StopWatchdog();
59int WatchdogMain(DWORD pid);
60
6aab2983
AK
61void InitSessionList();
62
a854d114
VK
63BOOL RegisterOnServer(const TCHAR *pszServer);
64
968031d9 65#if !defined(_WIN32)
203e9d8a 66void InitStaticSubagents();
5039dede
AK
67#endif
68
9f96fc88
VK
69#ifdef _WIN32
70extern TCHAR g_windowsServiceName[];
71extern TCHAR g_windowsServiceDisplayName[];
72#endif
73
f918b160
VK
74/**
75 * Messages generated by mc.pl (for UNIX version only)
76 */
5039dede
AK
77#ifndef _WIN32
78extern unsigned int g_dwNumMessages;
79extern const TCHAR *g_szMessages[];
80#endif
81
f918b160
VK
82/**
83 * Valid options for getopt()
84 */
5039dede 85#if defined(_WIN32)
f918b160 86#define VALID_OPTIONS "c:CdD:e:EfhHiIKM:n:N:P:r:RsSUvX:W:Z:"
5039dede 87#else
f918b160 88#define VALID_OPTIONS "c:CdD:fhKM:p:P:r:vX:W:Z:"
5039dede
AK
89#endif
90
f918b160
VK
91/**
92 * Actions
93 */
5039dede
AK
94#define ACTION_NONE 0
95#define ACTION_RUN_AGENT 1
96#define ACTION_INSTALL_SERVICE 2
97#define ACTION_REMOVE_SERVICE 3
98#define ACTION_START_SERVICE 4
99#define ACTION_STOP_SERVICE 5
100#define ACTION_CHECK_CONFIG 6
101#define ACTION_INSTALL_EVENT_SOURCE 7
102#define ACTION_REMOVE_EVENT_SOURCE 8
103#define ACTION_CREATE_CONFIG 9
104#define ACTION_HELP 10
9fcdfda7 105#define ACTION_RUN_WATCHDOG 11
f918b160 106#define ACTION_SHUTDOWN_EXT_AGENTS 12
5039dede 107
f918b160
VK
108/**
109 * Global variables
110 */
967893bb 111UINT32 g_dwFlags = AF_ENABLE_ACTIONS | AF_ENABLE_AUTOLOAD;
bf3b7f79 112TCHAR g_szLogFile[MAX_PATH] = AGENT_DEFAULT_LOG;
2b58ee20 113TCHAR g_szEncryptedSharedSecret[MAX_SECRET_LENGTH] = _T("");
bf3b7f79
VK
114TCHAR g_szSharedSecret[MAX_SECRET_LENGTH] = _T("admin");
115TCHAR g_szConfigFile[MAX_PATH] = AGENT_DEFAULT_CONFIG;
116TCHAR g_szFileStore[MAX_PATH] = AGENT_DEFAULT_FILE_STORE;
117TCHAR g_szDataDirectory[MAX_PATH] = AGENT_DEFAULT_DATA_DIR;
118TCHAR g_szPlatformSuffix[MAX_PSUFFIX_LENGTH] = _T("");
119TCHAR g_szConfigServer[MAX_DB_STRING] = _T("not_set");
120TCHAR g_szRegistrar[MAX_DB_STRING] = _T("not_set");
121TCHAR g_szListenAddress[MAX_PATH] = _T("*");
6ca3b41c 122TCHAR g_szConfigIncludeDir[MAX_PATH] = AGENT_DEFAULT_CONFIG_D;
0df58041 123TCHAR g_masterAgent[MAX_PATH] = _T("not_set");
9c786c0f 124UINT16 g_wListenPort = AGENT_LISTEN_PORT;
5039dede 125SERVER_INFO g_pServerList[MAX_SERVERS];
967893bb
VK
126UINT32 g_dwServerCount = 0;
127UINT32 g_dwExecTimeout = 2000; // External process execution timeout in milliseconds
128UINT32 g_dwSNMPTimeout = 3000;
5039dede 129time_t g_tmAgentStartTime;
967893bb
VK
130UINT32 g_dwStartupDelay = 0;
131UINT32 g_dwMaxSessions = 32;
e2e66145 132UINT32 g_debugLevel = (UINT32)NXCONFIG_UNINITIALIZED_VALUE;
9c786c0f
VK
133#ifdef _WIN32
134UINT16 g_sessionAgentPort = 28180;
135#else
136UINT16 g_sessionAgentPort = 0;
137#endif
e6c91aac 138Config *g_config;
5039dede 139#ifdef _WIN32
967893bb 140UINT32 g_dwIdleTimeout = 60; // Session idle timeout
5039dede 141#else
967893bb 142UINT32 g_dwIdleTimeout = 120; // Session idle timeout
5039dede
AK
143#endif
144
968031d9 145#if !defined(_WIN32)
bf3b7f79 146TCHAR g_szPidFile[MAX_PATH] = _T("/var/run/nxagentd.pid");
5039dede
AK
147#endif
148
8e334368
VK
149/**
150 * Static variables
151 */
bf3b7f79
VK
152static TCHAR *m_pszActionList = NULL;
153static TCHAR *m_pszShellActionList = NULL;
154static TCHAR *m_pszServerList = NULL;
155static TCHAR *m_pszControlServerList = NULL;
156static TCHAR *m_pszMasterServerList = NULL;
157static TCHAR *m_pszSubagentList = NULL;
158static TCHAR *m_pszExtParamList = NULL;
b5ded63e 159static TCHAR *m_pszExtListsList = NULL;
bf3b7f79 160static TCHAR *m_pszShExtParamList = NULL;
9795113c 161static TCHAR *m_pszParamProviderList = NULL;
204ace22 162static TCHAR *m_pszExtSubagentList = NULL;
83b20bab 163static TCHAR *m_pszAppAgentList = NULL;
967893bb 164static UINT32 m_dwEnabledCiphers = 0xFFFF;
5039dede
AK
165static THREAD m_thSessionWatchdog = INVALID_THREAD_HANDLE;
166static THREAD m_thListener = INVALID_THREAD_HANDLE;
167static THREAD m_thTrapSender = INVALID_THREAD_HANDLE;
0df58041 168static THREAD m_thMasterAgentListener = INVALID_THREAD_HANDLE;
040f4cef 169static TCHAR s_processToWaitFor[MAX_PATH] = _T("");
bf3b7f79 170static TCHAR m_szDumpDir[MAX_PATH] = _T("C:\\");
967893bb
VK
171static UINT32 m_dwMaxLogSize = 16384 * 1024;
172static UINT32 m_dwLogHistorySize = 4;
173static UINT32 m_dwLogRotationMode = NXLOG_ROTATION_BY_SIZE;
5945d50a 174static TCHAR m_szDailyLogFileSuffix[64] = _T("");
203e9d8a 175static Config *s_registry = NULL;
5a0d14cf 176static TCHAR s_executableName[MAX_PATH];
5039dede 177
968031d9 178#if defined(_WIN32)
5039dede
AK
179static CONDITION m_hCondShutdown = INVALID_CONDITION_HANDLE;
180#endif
181
968031d9 182#if !defined(_WIN32)
5039dede
AK
183static pid_t m_pid;
184#endif
185
f918b160
VK
186/**
187 * Configuration file template
188 */
5039dede
AK
189static NX_CFG_TEMPLATE m_cfgTemplate[] =
190{
e2e66145
VK
191 { _T("Action"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszActionList, NULL },
192 { _T("ActionShellExec"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszShellActionList, NULL },
193 { _T("AppAgent"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszAppAgentList, NULL },
194 { _T("ControlServers"), CT_STRING_LIST, ',', 0, 0, 0, &m_pszControlServerList, NULL },
195 { _T("CreateCrashDumps"), CT_BOOLEAN, 0, 0, AF_CATCH_EXCEPTIONS, 0, &g_dwFlags, NULL },
196 { _T("DataDirectory"), CT_STRING, 0, 0, MAX_PATH, 0, g_szDataDirectory, NULL },
197 { _T("DailyLogFileSuffix"), CT_STRING, 0, 0, MAX_PATH, 0, m_szDailyLogFileSuffix, NULL },
198 { _T("DebugLevel"), CT_LONG, 0, 0, 0, 0, &g_debugLevel, &g_debugLevel },
199 { _T("DumpDirectory"), CT_STRING, 0, 0, MAX_PATH, 0, m_szDumpDir, NULL },
200 { _T("EnableActions"), CT_BOOLEAN, 0, 0, AF_ENABLE_ACTIONS, 0, &g_dwFlags, NULL },
e2e66145
VK
201 { _T("EnabledCiphers"), CT_LONG, 0, 0, 0, 0, &m_dwEnabledCiphers, NULL },
202 { _T("EnableControlConnector"), CT_BOOLEAN, 0, 0, AF_ENABLE_CONTROL_CONNECTOR, 0, &g_dwFlags, NULL },
203 { _T("EnableProxy"), CT_BOOLEAN, 0, 0, AF_ENABLE_PROXY, 0, &g_dwFlags, NULL },
204 { _T("EnableSNMPProxy"), CT_BOOLEAN, 0, 0, AF_ENABLE_SNMP_PROXY, 0, &g_dwFlags, NULL },
205 { _T("EnableSubagentAutoload"), CT_BOOLEAN, 0, 0, AF_ENABLE_AUTOLOAD, 0, &g_dwFlags, NULL },
206 { _T("EnableWatchdog"), CT_BOOLEAN, 0, 0, AF_ENABLE_WATCHDOG, 0, &g_dwFlags, NULL },
207 { _T("ExecTimeout"), CT_LONG, 0, 0, 0, 0, &g_dwExecTimeout, NULL },
208 { _T("ExternalMasterAgent"), CT_STRING, 0, 0, MAX_PATH, 0, g_masterAgent, NULL },
209 { _T("ExternalParameter"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszExtParamList, NULL },
b5ded63e 210 { _T("ExternalList"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszExtListsList, NULL },
e2e66145
VK
211 { _T("ExternalParameterShellExec"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszShExtParamList, NULL },
212 { _T("ExternalParametersProvider"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszParamProviderList, NULL },
213 { _T("ExternalSubagent"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszExtSubagentList, NULL },
214 { _T("FileStore"), CT_STRING, 0, 0, MAX_PATH, 0, g_szFileStore, NULL },
215 { _T("FullCrashDumps"), CT_BOOLEAN, 0, 0, AF_WRITE_FULL_DUMP, 0, &g_dwFlags, NULL },
216 { _T("ListenAddress"), CT_STRING, 0, 0, MAX_PATH, 0, g_szListenAddress, NULL },
217 { _T("ListenPort"), CT_WORD, 0, 0, 0, 0, &g_wListenPort, NULL },
218 { _T("LogFile"), CT_STRING, 0, 0, MAX_PATH, 0, g_szLogFile, NULL },
219 { _T("LogHistorySize"), CT_LONG, 0, 0, 0, 0, &m_dwLogHistorySize, NULL },
220 { _T("LogRotationMode"), CT_LONG, 0, 0, 0, 0, &m_dwLogRotationMode, NULL },
221 { _T("LogUnresolvedSymbols"), CT_BOOLEAN, 0, 0, AF_LOG_UNRESOLVED_SYMBOLS, 0, &g_dwFlags, NULL },
222 { _T("MasterServers"), CT_STRING_LIST, ',', 0, 0, 0, &m_pszMasterServerList, NULL },
223 { _T("MaxLogSize"), CT_LONG, 0, 0, 0, 0, &m_dwMaxLogSize, NULL },
224 { _T("MaxSessions"), CT_LONG, 0, 0, 0, 0, &g_dwMaxSessions, NULL },
225 { _T("PlatformSuffix"), CT_STRING, 0, 0, MAX_PSUFFIX_LENGTH, 0, g_szPlatformSuffix, NULL },
226 { _T("RequireAuthentication"), CT_BOOLEAN, 0, 0, AF_REQUIRE_AUTH, 0, &g_dwFlags, NULL },
227 { _T("RequireEncryption"), CT_BOOLEAN, 0, 0, AF_REQUIRE_ENCRYPTION, 0, &g_dwFlags, NULL },
228 { _T("Servers"), CT_STRING_LIST, ',', 0, 0, 0, &m_pszServerList, NULL },
229 { _T("SessionIdleTimeout"), CT_LONG, 0, 0, 0, 0, &g_dwIdleTimeout, NULL },
2b58ee20 230 { _T("EncryptedSharedSecret"), CT_STRING, 0, 0, MAX_SECRET_LENGTH, 0, g_szEncryptedSharedSecret, NULL },
9c786c0f 231 { _T("SessionAgentPort"), CT_WORD, 0, 0, 0, 0, &g_sessionAgentPort, NULL },
e2e66145
VK
232 { _T("SharedSecret"), CT_STRING, 0, 0, MAX_SECRET_LENGTH, 0, g_szSharedSecret, NULL },
233 { _T("SNMPTimeout"), CT_LONG, 0, 0, 0, 0, &g_dwSNMPTimeout, NULL },
234 { _T("StartupDelay"), CT_LONG, 0, 0, 0, 0, &g_dwStartupDelay, NULL },
235 { _T("SubAgent"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszSubagentList, NULL },
236 { _T("TimeOut"), CT_IGNORE, 0, 0, 0, 0, NULL, NULL },
040f4cef 237 { _T("WaitForProcess"), CT_STRING, 0, 0, MAX_PATH, 0, s_processToWaitFor, NULL },
e2e66145 238 { _T(""), CT_END_OF_LIST, 0, 0, 0, 0, NULL, NULL }
5039dede
AK
239};
240
0f506caa
VK
241/**
242 * Help text
243 */
f3387429
VK
244static TCHAR m_szHelpText[] =
245 _T("Usage: nxagentd [options]\n")
246 _T("Where valid options are:\n")
247 _T(" -c <file> : Use configuration file <file> (default ") AGENT_DEFAULT_CONFIG _T(")\n")
248 _T(" -C : Check configuration file and exit\n")
249 _T(" -d : Run as daemon/service\n")
250 _T(" -D <level> : Set debug level (0..9)\n")
9f96fc88 251#ifdef _WIN32
f3387429 252 _T(" -e <name> : Windows event source name\n")
9f96fc88 253#endif
f3387429
VK
254 _T(" -f : Run in foreground\n")
255 _T(" -h : Display help and exit\n")
5039dede 256#ifdef _WIN32
f3387429
VK
257 _T(" -H : Hide agent's window when in standalone mode\n")
258 _T(" -i : Installed Windows service must be interactive\n")
259 _T(" -I : Install Windows service\n")
5039dede 260#endif
f918b160 261 _T(" -K : Shutdown all connected external sub-agents\n")
f3387429 262 _T(" -M <addr> : Download config from management server <addr>\n")
9f96fc88 263#ifdef _WIN32
f3387429
VK
264 _T(" -n <name> : Service name\n")
265 _T(" -N <name> : Service display name\n")
9f96fc88 266#endif
968031d9 267#if !defined(_WIN32)
f3387429 268 _T(" -p : Path to pid file (default: /var/run/nxagentd.pid)\n")
5039dede 269#endif
f3387429
VK
270 _T(" -P <text> : Set platform suffix to <text>\n")
271 _T(" -r <addr> : Register agent on management server <addr>\n")
5039dede 272#ifdef _WIN32
f3387429
VK
273 _T(" -R : Remove Windows service\n")
274 _T(" -s : Start Windows servive\n")
275 _T(" -S : Stop Windows service\n")
5039dede 276#endif
f3387429
VK
277 _T(" -v : Display version and exit\n")
278 _T("\n");
5039dede 279
f918b160
VK
280/**
281 * Save registry
282 */
203e9d8a
VK
283static void SaveRegistry()
284{
285 TCHAR regPath[MAX_PATH];
286 nx_strncpy(regPath, g_szDataDirectory, MAX_PATH - _tcslen(REGISTRY_FILE_NAME) - 1);
287 if (regPath[_tcslen(regPath) - 1] != FS_PATH_SEPARATOR_CHAR)
288 _tcscat(regPath, FS_PATH_SEPARATOR);
289 _tcscat(regPath, REGISTRY_FILE_NAME);
290
291 String xml = s_registry->createXml();
292 FILE *f = _tfopen(regPath, _T("w"));
293 if (f != NULL)
294 {
f3387429
VK
295#ifdef UNICODE
296 char *utf8xml = UTF8StringFromWideString((const WCHAR *)xml);
297 fputs(utf8xml, f);
4671afeb 298 safe_free(utf8xml);
f3387429
VK
299#else
300 fputs((const char *)xml, f);
301#endif
203e9d8a
VK
302 fclose(f);
303 }
304 else
305 {
f3387429 306 nxlog_write(MSG_REGISTRY_SAVE_FAILED, NXLOG_ERROR, "ss", regPath, _tcserror(errno));
203e9d8a
VK
307 }
308}
309
83b20bab
VK
310/**
311 * Open registry
312 */
203e9d8a
VK
313Config *OpenRegistry()
314{
315 s_registry->lock();
316 return s_registry;
317}
318
83b20bab
VK
319/**
320 * Close registry
321 */
203e9d8a
VK
322void CloseRegistry(bool modified)
323{
324 if (modified)
325 SaveRegistry();
326 s_registry->unlock();
327}
328
5039dede
AK
329#ifdef _WIN32
330
83b20bab
VK
331/**
332 * Get our own console window handle (an alternative to Microsoft's GetConsoleWindow)
333 */
203e9d8a 334static HWND GetConsoleHWND()
5039dede
AK
335{
336 HWND hWnd;
337 DWORD wpid, cpid;
338
339 cpid = GetCurrentProcessId();
340 while(1)
341 {
342 hWnd = FindWindowEx(NULL, NULL, _T("ConsoleWindowClass"), NULL);
343 if (hWnd == NULL)
344 break;
cc022855 345
5039dede
AK
346 GetWindowThreadProcessId(hWnd, &wpid);
347 if (cpid == wpid)
348 break;
349 }
350
351 return hWnd;
352}
353
83b20bab
VK
354/**
355 * Get proc address and write log file
356 */
5039dede
AK
357static FARPROC GetProcAddressAndLog(HMODULE hModule, LPCSTR procName)
358{
359 FARPROC ptr;
360
361 ptr = GetProcAddress(hModule, procName);
362 if ((ptr == NULL) && (g_dwFlags & AF_LOG_UNRESOLVED_SYMBOLS))
363 nxlog_write(MSG_NO_FUNCTION, EVENTLOG_WARNING_TYPE, "s", procName);
364 return ptr;
365}
366
83b20bab
VK
367/**
368 * Shutdown thread (created by H_RestartAgent)
369 */
5039dede
AK
370static THREAD_RESULT THREAD_CALL ShutdownThread(void *pArg)
371{
8e954797 372 DebugPrintf(INVALID_INDEX, 1, _T("Shutdown thread started"));
5039dede
AK
373 Shutdown();
374 ExitProcess(0);
375 return THREAD_OK; // Never reached
376}
377
378#endif /* _WIN32 */
379
134c8b79 380
acc04d96
VK
381/**
382 * Restart agent
383 */
6173bea8 384static LONG H_RestartAgent(const TCHAR *action, StringList *args, const TCHAR *data)
5039dede 385{
5b2c3e2d
VK
386 DebugPrintf(INVALID_INDEX, 1, _T("H_RestartAgent() called"));
387
5039dede 388 TCHAR szCmdLine[4096], szPlatformSuffixOption[MAX_PSUFFIX_LENGTH + 16];
5039dede
AK
389
390 if (g_szPlatformSuffix[0] != 0)
391 {
392 _sntprintf(szPlatformSuffixOption, MAX_PSUFFIX_LENGTH + 16, _T("-P \"%s\" "), g_szPlatformSuffix);
393 }
394 else
395 {
396 szPlatformSuffixOption[0] = 0;
397 }
398
399#ifdef _WIN32
5a0d14cf 400 _sntprintf(szCmdLine, 4096, _T("\"%s\" -c \"%s\" -n \"%s\" -e \"%s\" %s%s%s%s%s-D %d %s-X %u"), s_executableName,
93599cfd
VK
401 g_szConfigFile, g_windowsServiceName, g_windowsEventSourceName,
402 (g_dwFlags & AF_DAEMON) ? _T("-d ") : _T(""),
5039dede
AK
403 (g_dwFlags & AF_HIDE_WINDOW) ? _T("-H ") : _T(""),
404 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T("-M ") : _T(""),
405 (g_dwFlags & AF_CENTRAL_CONFIG) ? g_szConfigServer : _T(""),
406 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T(" ") : _T(""),
c303351c 407 g_debugLevel, szPlatformSuffixOption,
5039dede 408 (g_dwFlags & AF_DAEMON) ? 0 : GetCurrentProcessId());
c303351c 409 DebugPrintf(INVALID_INDEX, 1, _T("Restarting agent with command line '%s'"), szCmdLine);
5039dede 410
5a0d14cf
VK
411 DWORD dwResult;
412 STARTUPINFO si;
413 PROCESS_INFORMATION pi;
cc022855 414
5039dede
AK
415 // Fill in process startup info structure
416 memset(&si, 0, sizeof(STARTUPINFO));
417 si.cb = sizeof(STARTUPINFO);
418
419 // Create new process
cc022855 420 if (!CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE,
5039dede
AK
421 (g_dwFlags & AF_DAEMON) ? (CREATE_NO_WINDOW | DETACHED_PROCESS) : (CREATE_NEW_CONSOLE),
422 NULL, NULL, &si, &pi))
423 {
424 nxlog_write(MSG_CREATE_PROCESS_FAILED, EVENTLOG_ERROR_TYPE, "se", szCmdLine, GetLastError());
425 dwResult = ERR_EXEC_FAILED;
426 }
427 else
428 {
429 // Close all handles
430 CloseHandle(pi.hThread);
431 CloseHandle(pi.hProcess);
432 dwResult = ERR_SUCCESS;
433 }
434 if ((dwResult == ERR_SUCCESS) && (!(g_dwFlags & AF_DAEMON)))
435 {
436 if (g_dwFlags & AF_HIDE_WINDOW)
437 {
438 ConditionSet(m_hCondShutdown);
439 }
440 else
441 {
442 ThreadCreate(ShutdownThread, 0, NULL);
443 }
444 }
445 return dwResult;
446#else
5a0d14cf 447 _sntprintf(szCmdLine, 4096, _T("\"%s\" -c \"%s\" %s%s%s%s-D %d %s-X %lu"), s_executableName,
5039dede
AK
448 g_szConfigFile, (g_dwFlags & AF_DAEMON) ? _T("-d ") : _T(""),
449 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T("-M ") : _T(""),
450 (g_dwFlags & AF_CENTRAL_CONFIG) ? g_szConfigServer : _T(""),
451 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T(" ") : _T(""),
53c96e2d 452 (int)g_debugLevel, szPlatformSuffixOption,
5039dede 453 (unsigned long)m_pid);
5b2c3e2d 454 DebugPrintf(INVALID_INDEX, 1, _T("Restarting agent with command line '%s'"), szCmdLine);
9fcdfda7 455 return ExecuteCommand(szCmdLine, NULL, NULL);
5039dede 456#endif
5039dede
AK
457}
458
acc04d96
VK
459/**
460 * This function writes message from subagent to agent's log
461 */
c303351c 462static void WriteSubAgentMsg(int logLevel, int debugLevel, const TCHAR *pszMsg)
5039dede 463{
c303351c 464 if (logLevel == EVENTLOG_DEBUG_TYPE)
5039dede 465 {
15e11d1b 466 if (debugLevel <= (int)g_debugLevel)
c303351c 467 nxlog_write(MSG_DEBUG, EVENTLOG_DEBUG_TYPE, "s", pszMsg);
5039dede
AK
468 }
469 else
470 {
c303351c 471 nxlog_write(MSG_SUBAGENT_MSG, logLevel, "s", pszMsg);
5039dede
AK
472 }
473}
474
acc04d96
VK
475/**
476 * Signal handler for UNIX platforms
477 */
968031d9 478#if !defined(_WIN32)
5039dede
AK
479
480static THREAD_RESULT THREAD_CALL SignalHandler(void *pArg)
481{
482 sigset_t signals;
483 int nSignal;
484
485 sigemptyset(&signals);
486 sigaddset(&signals, SIGTERM);
487 sigaddset(&signals, SIGINT);
5039dede
AK
488 sigaddset(&signals, SIGSEGV);
489 sigaddset(&signals, SIGHUP);
490 sigaddset(&signals, SIGUSR1);
491 sigaddset(&signals, SIGUSR2);
95e2329a
VK
492#if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
493 sigaddset(&signals, SIGPIPE);
494#endif
5039dede
AK
495
496 sigprocmask(SIG_BLOCK, &signals, NULL);
497
498 while(1)
499 {
500 if (sigwait(&signals, &nSignal) == 0)
501 {
502 switch(nSignal)
503 {
504 case SIGTERM:
505 case SIGINT:
506 goto stop_handler;
507 case SIGSEGV:
508 abort();
509 break;
510 default:
511 break;
512 }
513 }
514 else
515 {
516 ThreadSleepMs(100);
517 }
518 }
519
520stop_handler:
521 sigprocmask(SIG_UNBLOCK, &signals, NULL);
522 return THREAD_OK;
523}
524
525#endif
526
acc04d96
VK
527/**
528 * Load platform subagent
529 */
530static void LoadPlatformSubagent()
5039dede 531{
acc04d96
VK
532#ifdef _WIN32
533 LoadSubAgent(_T("WINNT.NSM"));
5039dede 534#else
968031d9 535#if HAVE_SYS_UTSNAME_H && !defined(_STATIC_AGENT)
5039dede 536 struct utsname un;
f3387429 537 TCHAR szName[MAX_PATH];
5039dede
AK
538 int i;
539
540 if (uname(&un) != -1)
541 {
542 // Convert system name to lowercase
543 for(i = 0; un.sysname[i] != 0; i++)
544 un.sysname[i] = tolower(un.sysname[i]);
545 if (!strcmp(un.sysname, "hp-ux"))
546 strcpy(un.sysname, "hpux");
f31c22b3 547 _sntprintf(szName, MAX_PATH, _T("%hs.nsm"), un.sysname);
5039dede
AK
548 LoadSubAgent(szName);
549 }
550#endif
5039dede 551#endif
acc04d96 552}
5039dede 553
acc04d96
VK
554/**
555 * Send file to server (subagent API)
556 */
cc022855 557static bool SendFileToServer(void *session, UINT32 requestId, const TCHAR *file, long offset)
6173bea8 558{
4685a2ad 559 if (session == NULL)
0137b9f7 560 return false;
cc022855 561 return ((CommSession *)session)->sendFile(requestId, file, offset);
6173bea8
VK
562}
563
23d3d35d 564/**
565 * Goes throught sesion list and executs on each object handler while it returns true
566 */
567static bool EnumerateSessionsBySubagent(bool (* pHandler)(AbstractCommSession *, void* ), void *data)
568{
fd1d4ecf 569 bool ret = false;
23d3d35d 570 MutexLock(g_hSessionListAccess);
571 for(UINT32 i = 0; i < g_dwMaxSessions; i++)
572 {
573 if(!pHandler(g_pSessionList[i], data))
fd1d4ecf 574 {
575 ret = true;
576 break;
577 }
23d3d35d 578 }
579 MutexUnlock(g_hSessionListAccess);
fd1d4ecf 580 return ret;
23d3d35d 581}
582
83b20bab
VK
583/**
584 * Parser server list
585 */
968031d9
VK
586static void ParseServerList(TCHAR *serverList, BOOL isControl, BOOL isMaster)
587{
588 TCHAR *pItem, *pEnd;
589
590 for(pItem = pEnd = serverList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
591 {
f3387429 592 pEnd = _tcschr(pItem, _T(','));
968031d9
VK
593 if (pEnd != NULL)
594 *pEnd = 0;
595 StrStrip(pItem);
596
967893bb 597 UINT32 ipAddr, netMask;
968031d9
VK
598
599 TCHAR *mask = _tcschr(pItem, _T('/'));
600 if (mask != NULL)
601 {
602 *mask = 0;
603 mask++;
f3387429 604 ipAddr = _t_inet_addr(pItem);
968031d9
VK
605
606 TCHAR *eptr;
607 int bits = _tcstol(mask, &eptr, 10);
608 if ((*eptr == 0) && (bits >= 0) && (bits <= 32))
609 {
13dbd3dd 610 netMask = (bits > 0) ? htonl(0xFFFFFFFF << (32 - bits)) : 0;
968031d9
VK
611 }
612 else
613 {
614 ipAddr = INADDR_NONE;
615 if (!(g_dwFlags & AF_DAEMON))
f3387429 616 _tprintf(_T("Invalid network mask %s\n"), mask);
968031d9
VK
617 }
618 }
619 else
620 {
621 ipAddr = ResolveHostName(pItem);
622 if (ipAddr == INADDR_ANY)
623 ipAddr = INADDR_NONE;
624 netMask = 0xFFFFFFFF;
625 }
926c5e72 626 if (ipAddr == INADDR_NONE)
968031d9
VK
627 {
628 if (!(g_dwFlags & AF_DAEMON))
f3387429 629 _tprintf(_T("Invalid server address '%s'\n"), pItem);
968031d9
VK
630 }
631 else
632 {
967893bb 633 UINT32 i;
968031d9
VK
634
635 for(i = 0; i < g_dwServerCount; i++)
636 if ((g_pServerList[i].dwIpAddr == ipAddr) && (g_pServerList[i].dwNetMask == netMask))
637 break;
638 if (i == g_dwServerCount)
639 {
640 g_dwServerCount++;
641 g_pServerList[i].dwIpAddr = ipAddr;
642 g_pServerList[i].dwNetMask = netMask;
643 }
644 g_pServerList[i].bMasterServer = isMaster;
645 g_pServerList[i].bControlServer = isControl;
646 }
647 }
648 free(serverList);
649}
650
ed950274
VK
651/**
652 * Agent initialization
653 */
c6fbf758 654BOOL Initialize()
5039dede 655{
bf3b7f79
VK
656 TCHAR *pItem, *pEnd;
657 TCHAR regPath[MAX_PATH];
5039dede 658
e2e66145
VK
659 if (g_debugLevel == (UINT32)NXCONFIG_UNINITIALIZED_VALUE)
660 g_debugLevel = 0;
661
f31c22b3
VK
662#ifndef _WIN32
663 if (!_tcscmp(g_szDataDirectory, _T("{default}")))
664 {
665 const TCHAR *homeDir = _tgetenv(_T("NETXMS_HOME"));
666 if (homeDir != NULL)
667 {
668 _sntprintf(g_szDataDirectory, MAX_PATH, _T("%s/var/netxms"), homeDir);
669 }
670 else
671 {
f515e13a 672 nx_strncpy(g_szDataDirectory, _T("/var/netxms"), MAX_PATH);
f31c22b3
VK
673 }
674 }
675#endif
676
5039dede 677 // Open log file
4addc3a3
VK
678 if (!(g_dwFlags & AF_USE_SYSLOG))
679 {
5945d50a 680 if (!nxlog_set_rotation_policy((int)m_dwLogRotationMode, (int)m_dwMaxLogSize, (int)m_dwLogHistorySize, m_szDailyLogFileSuffix))
4addc3a3 681 if (!(g_dwFlags & AF_DAEMON))
bf3b7f79 682 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
4addc3a3 683 }
9fcdfda7
VK
684 if (!nxlog_open((g_dwFlags & AF_USE_SYSLOG) ? NXAGENTD_SYSLOG_NAME : g_szLogFile,
685 ((g_dwFlags & AF_USE_SYSLOG) ? NXLOG_USE_SYSLOG : 0) |
686 ((g_dwFlags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
687 _T("NXAGENTD.EXE"),
5039dede 688#ifdef _WIN32
9fcdfda7 689 0, NULL))
5039dede 690#else
9fcdfda7 691 g_dwNumMessages, g_szMessages))
5039dede 692#endif
9fcdfda7 693 {
bf3b7f79 694 _ftprintf(stderr, _T("FATAL ERROR: Cannot open log file\n"));
9fcdfda7
VK
695 return FALSE;
696 }
203e9d8a
VK
697 nxlog_write(MSG_USE_CONFIG_D, NXLOG_INFO, "s", g_szConfigIncludeDir);
698 nxlog_write(MSG_DEBUG_LEVEL, NXLOG_INFO, "d", g_debugLevel);
699
0df58041
VK
700 if (_tcscmp(g_masterAgent, _T("not_set")))
701 {
702 g_dwFlags |= AF_SUBAGENT_LOADER;
703 DebugPrintf(INVALID_INDEX, 1, _T("Switched to external subagent loader mode, master agent address is %s"), g_masterAgent);
704 }
705
f31c22b3
VK
706 DebugPrintf(INVALID_INDEX, 1, _T("Data directory: %s"), g_szDataDirectory);
707
203e9d8a
VK
708 // Initialize persistent storage
709 s_registry = new Config;
710 s_registry->setTopLevelTag(_T("registry"));
711 nx_strncpy(regPath, g_szDataDirectory, MAX_PATH - _tcslen(REGISTRY_FILE_NAME) - 1);
712 if (regPath[_tcslen(regPath) - 1] != FS_PATH_SEPARATOR_CHAR)
713 _tcscat(regPath, FS_PATH_SEPARATOR);
714 _tcscat(regPath, REGISTRY_FILE_NAME);
715 if (!s_registry->loadXmlConfig(regPath, "registry"))
716 {
717 nxlog_write(MSG_REGISTRY_LOAD_FAILED, NXLOG_ERROR, "s", regPath);
718 SaveRegistry();
719 }
5039dede
AK
720
721#ifdef _WIN32
722 WSADATA wsaData;
1ddf3f0c
VK
723 int wrc = WSAStartup(MAKEWORD(2, 2), &wsaData);
724 if (wrc != 0)
5039dede 725 {
1ddf3f0c 726 nxlog_write(MSG_WSASTARTUP_FAILED, NXLOG_ERROR, "e", wrc);
5039dede
AK
727 return FALSE;
728 }
5039dede
AK
729#endif
730
5039dede 731 // Initialize API for subagents
23d3d35d 732 InitSubAgentAPI(WriteSubAgentMsg, SendTrap, SendTrap, EnumerateSessionsBySubagent, SendFileToServer, PushData);
bf3b7f79 733 DebugPrintf(INVALID_INDEX, 1, _T("Subagent API initialized"));
5039dede
AK
734
735 // Initialize cryptografy
6468147c 736 if (!InitCryptoLib(m_dwEnabledCiphers, DebugPrintfCallback))
5039dede
AK
737 {
738 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError());
739 return FALSE;
740 }
741
0df58041
VK
742 if (!(g_dwFlags & AF_SUBAGENT_LOADER))
743 {
744 InitSessionList();
745
746 // Initialize built-in parameters
747 if (!InitParameterList())
748 return FALSE;
5039dede 749
968031d9 750 // Parse server lists
0df58041 751 if (m_pszServerList != NULL)
968031d9 752 ParseServerList(m_pszServerList, FALSE, FALSE);
0df58041 753 if (m_pszControlServerList != NULL)
968031d9
VK
754 ParseServerList(m_pszControlServerList, TRUE, FALSE);
755 if (m_pszMasterServerList != NULL)
756 ParseServerList(m_pszMasterServerList, TRUE, TRUE);
5039dede 757
0df58041 758 // Add built-in actions
f3387429 759 AddAction(_T("Agent.Restart"), AGENT_ACTION_SUBAGENT, NULL, H_RestartAgent, _T("CORE"), _T("Restart agent"));
5039dede 760
0df58041 761 // Load platform subagents
968031d9 762#if !defined(_WIN32)
0df58041 763 InitStaticSubagents();
5039dede 764#endif
0df58041
VK
765 if (g_dwFlags & AF_ENABLE_AUTOLOAD)
766 {
0df58041 767 LoadPlatformSubagent();
0df58041
VK
768 }
769 }
5039dede
AK
770
771 // Wait for external process if requested
040f4cef 772 if (s_processToWaitFor[0] != 0)
5039dede 773 {
040f4cef
VK
774 DebugPrintf(INVALID_INDEX, 1, _T("Waiting for process %s"), s_processToWaitFor);
775 if (!WaitForProcess(s_processToWaitFor))
776 nxlog_write(MSG_WAITFORPROCESS_FAILED, EVENTLOG_ERROR_TYPE, "s", s_processToWaitFor);
5039dede
AK
777 }
778
6468147c 779 DBSetDebugPrintCallback(DebugPrintfCallback);
b34606f7
VK
780 DBInit(MSG_DB_LIBRARY, MSG_SQL_ERROR);
781
5039dede
AK
782 // Load other subagents
783 if (m_pszSubagentList != NULL)
784 {
e6c91aac 785 for(pItem = pEnd = m_pszSubagentList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede 786 {
f3387429 787 pEnd = _tcschr(pItem, _T('\n'));
5039dede
AK
788 if (pEnd != NULL)
789 *pEnd = 0;
790 StrStrip(pItem);
791 LoadSubAgent(pItem);
792 }
793 free(m_pszSubagentList);
794 }
795
796 // Parse action list
797 if (m_pszActionList != NULL)
798 {
e6c91aac 799 for(pItem = pEnd = m_pszActionList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede 800 {
f3387429 801 pEnd = _tcschr(pItem, _T('\n'));
5039dede
AK
802 if (pEnd != NULL)
803 *pEnd = 0;
804 StrStrip(pItem);
805 if (!AddActionFromConfig(pItem, FALSE))
806 nxlog_write(MSG_ADD_ACTION_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
807 }
808 free(m_pszActionList);
809 }
810 if (m_pszShellActionList != NULL)
811 {
e6c91aac 812 for(pItem = pEnd = m_pszShellActionList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede 813 {
bf3b7f79 814 pEnd = _tcschr(pItem, _T('\n'));
5039dede
AK
815
816 if (pEnd != NULL)
817 *pEnd = 0;
818 StrStrip(pItem);
819 if (!AddActionFromConfig(pItem, TRUE))
820 nxlog_write(MSG_ADD_ACTION_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
821 }
822 free(m_pszShellActionList);
823 }
824
825 // Parse external parameters list
826 if (m_pszExtParamList != NULL)
827 {
e6c91aac 828 for(pItem = pEnd = m_pszExtParamList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede 829 {
f3387429 830 pEnd = _tcschr(pItem, _T('\n'));
5039dede
AK
831 if (pEnd != NULL)
832 *pEnd = 0;
833 StrStrip(pItem);
b5ded63e 834 if (!AddExternalParameter(pItem, FALSE, FALSE))
5039dede
AK
835 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
836 }
837 free(m_pszExtParamList);
838 }
839 if (m_pszShExtParamList != NULL)
840 {
e6c91aac 841 for(pItem = pEnd = m_pszShExtParamList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede 842 {
f3387429 843 pEnd = _tcschr(pItem, _T('\n'));
5039dede
AK
844 if (pEnd != NULL)
845 *pEnd = 0;
846 StrStrip(pItem);
b5ded63e 847 if (!AddExternalParameter(pItem, TRUE, FALSE))
5039dede
AK
848 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
849 }
850 free(m_pszShExtParamList);
851 }
852
b5ded63e
AK
853 // Parse external lists
854 if (m_pszExtListsList != NULL)
855 {
856 for(pItem = pEnd = m_pszExtListsList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
857 {
858 pEnd = _tcschr(pItem, _T('\n'));
859 if (pEnd != NULL)
860 *pEnd = 0;
861 StrStrip(pItem);
862 if (!AddExternalParameter(pItem, FALSE, TRUE))
863 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
864 }
865 free(m_pszExtListsList);
866 }
867
9795113c
VK
868 // Parse external parameters providers list
869 if (m_pszParamProviderList != NULL)
870 {
871 for(pItem = pEnd = m_pszParamProviderList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
872 {
f3387429 873 pEnd = _tcschr(pItem, _T('\n'));
9795113c
VK
874 if (pEnd != NULL)
875 *pEnd = 0;
876 StrStrip(pItem);
877 if (!AddParametersProvider(pItem))
878 nxlog_write(MSG_ADD_PARAM_PROVIDER_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
879 }
880 free(m_pszParamProviderList);
881 }
882
204ace22 883 // Parse external subagents list
0df58041 884 if (!(g_dwFlags & AF_SUBAGENT_LOADER) && (m_pszExtSubagentList != NULL))
204ace22
VK
885 {
886 for(pItem = pEnd = m_pszExtSubagentList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
887 {
f3387429 888 pEnd = _tcschr(pItem, _T('\n'));
204ace22
VK
889 if (pEnd != NULL)
890 *pEnd = 0;
891 StrStrip(pItem);
892 if (!AddExternalSubagent(pItem))
893 nxlog_write(MSG_ADD_EXTERNAL_SUBAGENT_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
894 }
895 free(m_pszExtSubagentList);
896 }
897
83b20bab
VK
898 // Parse application agents list
899 if (!(g_dwFlags & AF_SUBAGENT_LOADER) && (m_pszAppAgentList != NULL))
900 {
901 for(pItem = pEnd = m_pszAppAgentList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
902 {
903 pEnd = _tcschr(pItem, _T('\n'));
904 if (pEnd != NULL)
905 *pEnd = 0;
906 StrStrip(pItem);
907 RegisterApplicationAgent(pItem);
908 }
909 free(m_pszAppAgentList);
910 }
911
5039dede
AK
912 ThreadSleep(1);
913
914 // If StartupDelay is greater than zero, then wait
915 if (g_dwStartupDelay > 0)
916 {
917 if (g_dwFlags & AF_DAEMON)
918 {
919 ThreadSleep(g_dwStartupDelay);
920 }
921 else
922 {
967893bb 923 UINT32 i;
5039dede 924
f3387429 925 _tprintf(_T("XXXXXX%*s]\rWAIT ["), g_dwStartupDelay, _T(" "));
5039dede
AK
926 fflush(stdout);
927 for(i = 0; i < g_dwStartupDelay; i++)
928 {
929 ThreadSleep(1);
f3387429 930 _puttc(_T('.'), stdout);
5039dede
AK
931 fflush(stdout);
932 }
f3387429 933 _tprintf(_T("\n"));
5039dede
AK
934 }
935 }
936
9795113c
VK
937 StartParamProvidersPoller();
938
5039dede
AK
939 // Agent start time
940 g_tmAgentStartTime = time(NULL);
941
29bb6817 942 m_thTrapSender = ThreadCreateEx(TrapSender, 0, NULL);
0df58041
VK
943 if (g_dwFlags & AF_SUBAGENT_LOADER)
944 {
945 m_thMasterAgentListener = ThreadCreateEx(MasterAgentListener, 0, NULL);
946 }
947 else
948 {
949 // Start network listener and session watchdog
950 m_thListener = ThreadCreateEx(ListenerThread, 0, NULL);
951 m_thSessionWatchdog = ThreadCreateEx(SessionWatchdog, 0, NULL);
0bd64860 952 StartPushConnector();
a2a24e9d 953 StartStorageDiscoveryConnector();
9c786c0f 954 StartSessionAgentConnector();
f918b160
VK
955 if (g_dwFlags & AF_ENABLE_CONTROL_CONNECTOR)
956 {
957 StartControlConnector();
958 }
a854d114
VK
959
960 if (g_dwFlags & AF_REGISTER)
961 {
962 RegisterOnServer(g_szRegistrar);
963 }
964 }
5039dede 965
968031d9 966#if defined(_WIN32)
5039dede
AK
967 m_hCondShutdown = ConditionCreate(TRUE);
968#endif
969 ThreadSleep(1);
970
9fcdfda7 971 // Start watchdog process
0df58041
VK
972 if (!(g_dwFlags & AF_SUBAGENT_LOADER))
973 {
974 if (g_dwFlags & AF_ENABLE_WATCHDOG)
975 StartWatchdog();
976 }
9fcdfda7 977
80f2318b 978 //Delete file for upgrade if exists
979 Config *registry = OpenRegistry();
980 const TCHAR* szFullPath = registry->getValue(_T("/upgrade/file"));
981 if(szFullPath != NULL){
982 _tremove(szFullPath);
983 }
984 registry->deleteEntry(_T("/upgrade/file"));
985 CloseRegistry(true);
986
c6fbf758
VK
987 delete g_config;
988
5039dede
AK
989 return TRUE;
990}
991
605fc935
VK
992/**
993 * Shutdown agent
994 */
0df58041 995void Shutdown()
5039dede 996{
8e954797 997 DebugPrintf(INVALID_INDEX, 2, _T("Shutdown() called"));
9fcdfda7
VK
998 if (g_dwFlags & AF_ENABLE_WATCHDOG)
999 StopWatchdog();
1000
5039dede 1001 g_dwFlags |= AF_SHUTDOWN;
0df58041
VK
1002
1003 if (g_dwFlags & AF_SUBAGENT_LOADER)
1004 {
639088d4
VK
1005 // TODO: shall we inform master agent listener about shutdown?
1006 //ThreadJoin(m_thMasterAgentListener);
0df58041
VK
1007 }
1008 else
1009 {
1010 ShutdownTrapSender();
1011 ThreadJoin(m_thSessionWatchdog);
1012 ThreadJoin(m_thListener);
0df58041 1013 }
29bb6817 1014 ThreadJoin(m_thTrapSender);
5039dede
AK
1015
1016 UnloadAllSubAgents();
1017 nxlog_write(MSG_AGENT_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
1018 nxlog_close();
1019
1020 // Notify main thread about shutdown
1021#ifdef _WIN32
1022 ConditionSet(m_hCondShutdown);
1023#endif
cc022855 1024
5039dede 1025 // Remove PID file
968031d9 1026#if !defined(_WIN32)
f3387429 1027 _tremove(g_szPidFile);
5039dede
AK
1028#endif
1029}
1030
605fc935
VK
1031/**
1032 * Common Main()
1033 */
8ec102ac 1034void Main()
5039dede 1035{
8ec102ac 1036 nxlog_write(MSG_AGENT_STARTED, NXLOG_INFO, NULL);
5039dede
AK
1037
1038 if (g_dwFlags & AF_DAEMON)
1039 {
968031d9 1040#if defined(_WIN32)
5039dede
AK
1041 ConditionWait(m_hCondShutdown, INFINITE);
1042#else
1043 StartMainLoop(SignalHandler, NULL);
1044#endif
1045 }
1046 else
1047 {
1048#if defined(_WIN32)
1049 if (g_dwFlags & AF_HIDE_WINDOW)
1050 {
1051 HWND hWnd;
1052
1053 hWnd = GetConsoleHWND();
1054 if (hWnd != NULL)
1055 ShowWindow(hWnd, SW_HIDE);
1056 ConditionWait(m_hCondShutdown, INFINITE);
1057 ThreadSleep(1);
1058 }
1059 else
1060 {
f3387429 1061 _tprintf(_T("Agent running. Press ESC to shutdown.\n"));
5039dede
AK
1062 while(1)
1063 {
3973f74b 1064 if (_getch() == 27)
5039dede
AK
1065 break;
1066 }
f3387429 1067 _tprintf(_T("Agent shutting down...\n"));
5039dede
AK
1068 Shutdown();
1069 }
5039dede 1070#else
f3387429 1071 _tprintf(_T("Agent running. Press Ctrl+C to shutdown.\n"));
5039dede 1072 StartMainLoop(SignalHandler, NULL);
f3387429 1073 _tprintf(_T("\nStopping agent...\n"));
5039dede
AK
1074#endif
1075 }
1076}
1077
605fc935
VK
1078/**
1079 * Do necessary actions on agent restart
1080 */
967893bb 1081static void DoRestartActions(UINT32 dwOldPID)
5039dede
AK
1082{
1083#if defined(_WIN32)
1084 if (dwOldPID == 0)
1085 {
1086 // Service
1087 StopAgentService();
1088 WaitForService(SERVICE_STOPPED);
1089 StartAgentService();
1090 ExitProcess(0);
1091 }
1092 else
1093 {
1094 HANDLE hProcess;
1095
1096 hProcess = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, dwOldPID);
1097 if (hProcess != NULL)
1098 {
1099 if (WaitForSingleObject(hProcess, 60000) == WAIT_TIMEOUT)
1100 {
1101 TerminateProcess(hProcess, 0);
1102 }
1103 CloseHandle(hProcess);
1104 }
1105 }
5039dede
AK
1106#else
1107 int i;
1108
1109 kill(dwOldPID, SIGTERM);
1110 for(i = 0; i < 30; i++)
1111 {
1112 sleep(2);
1113 if (kill(dwOldPID, SIGCONT) == -1)
1114 break;
1115 }
cc022855 1116
5039dede
AK
1117 // Kill previous instance of agent if it's still running
1118 if (i == 30)
1119 kill(dwOldPID, SIGKILL);
1120#endif
1121}
1122
605fc935
VK
1123/**
1124 * Create configuration file
1125 */
f3387429
VK
1126static int CreateConfig(const char *pszServer, const char *pszLogFile, const char *pszFileStore,
1127 const char *configIncludeDir, int iNumSubAgents, char **ppszSubAgentList)
5039dede
AK
1128{
1129 FILE *fp;
1130 time_t currTime;
1131 int i;
1132
1133 if (_taccess(g_szConfigFile, 0) == 0)
1134 return 0; // File already exist, we shouldn't overwrite it
1135
1136 fp = _tfopen(g_szConfigFile, _T("w"));
1137 if (fp != NULL)
1138 {
1139 currTime = time(NULL);
1140 _ftprintf(fp, _T("#\n# NetXMS agent configuration file\n# Created by agent installer at %s#\n\n"),
1141 _tctime(&currTime));
f3387429 1142 _ftprintf(fp, _T("MasterServers = %hs\nConfigIncludeDir = %hs\nLogFile = %hs\nFileStore = %hs\n"),
48dd3c80 1143 pszServer, configIncludeDir, pszLogFile, pszFileStore);
5039dede 1144 for(i = 0; i < iNumSubAgents; i++)
f3387429 1145 _ftprintf(fp, _T("SubAgent = %hs\n"), ppszSubAgentList[i]);
5039dede
AK
1146 fclose(fp);
1147 }
1148 return (fp != NULL) ? 0 : 2;
1149}
1150
ed950274
VK
1151/**
1152 * Init config
1153 */
e6c91aac
VK
1154static void InitConfig()
1155{
1156 g_config = new Config();
8a0dffac 1157 g_config->setTopLevelTag(_T("config"));
e6c91aac
VK
1158}
1159
f918b160
VK
1160/**
1161 * Initiate shutdown of connected external subagents
1162 */
1163static void InitiateExtSubagentShutdown()
1164{
1165 CSCPMessage msg;
1166 msg.SetCode(CMD_SHUTDOWN);
1167 if (SendControlMessage(&msg))
1168 _tprintf(_T("Control message sent successfully to master agent\n"));
1169 else
1170 _tprintf(_T("ERROR: Unable to send control message to master agent\n"));
1171}
1172
2295e8f5
VK
1173/**
1174 * Application entry point
1175 */
5039dede
AK
1176int main(int argc, char *argv[])
1177{
1178 int ch, iExitCode = 0, iAction = ACTION_RUN_AGENT;
1179 BOOL bRestart = FALSE;
967893bb 1180 UINT32 dwOldPID, dwMainPID;
f3387429 1181 char *eptr;
5039dede 1182#ifdef _WIN32
bf3b7f79 1183 TCHAR szModuleName[MAX_PATH];
1621a079
VK
1184 HKEY hKey;
1185 DWORD dwSize;
1186#else
f3387429 1187 TCHAR *pszEnv;
5039dede
AK
1188#endif
1189
2295e8f5
VK
1190#ifdef _WIN32
1191 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
1192#endif
1193
d40b6356 1194#if defined(__sun) || defined(_AIX) || defined(__hpux)
1685d106
VK
1195 signal(SIGPIPE, SIG_IGN);
1196 signal(SIGHUP, SIG_IGN);
1685d106
VK
1197 signal(SIGQUIT, SIG_IGN);
1198 signal(SIGUSR1, SIG_IGN);
1199 signal(SIGUSR2, SIG_IGN);
1200#endif
1201
5039dede 1202 InitThreadLibrary();
9fcdfda7
VK
1203
1204#ifdef NETXMS_MEMORY_DEBUG
1205 InitMemoryDebugger();
1206#endif
cc022855 1207
5039dede
AK
1208 // Set locale to C. It shouldn't be needed, according to
1209 // documentation, but I've seen the cases when agent formats
1210 // floating point numbers by sprintf inserting comma in place
1211 // of a dot, as set by system's regional settings.
c1099678
VK
1212#if HAVE_SETLOCALE
1213 setlocale(LC_NUMERIC, "C");
5039dede
AK
1214#endif
1215
1621a079
VK
1216 // Check for alternate config file location
1217#ifdef _WIN32
1218 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Agent"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
1219 {
1220 dwSize = MAX_PATH * sizeof(TCHAR);
1221 RegQueryValueEx(hKey, _T("ConfigFile"), NULL, NULL, (BYTE *)g_szConfigFile, &dwSize);
42acd918 1222 dwSize = MAX_PATH * sizeof(TCHAR);
1621a079
VK
1223 RegQueryValueEx(hKey, _T("ConfigIncludeDir"), NULL, NULL, (BYTE *)g_szConfigIncludeDir, &dwSize);
1224 RegCloseKey(hKey);
1225 }
1226#else
1227 pszEnv = _tgetenv(_T("NXAGENTD_CONFIG"));
1228 if (pszEnv != NULL)
1229 nx_strncpy(g_szConfigFile, pszEnv, MAX_PATH);
1230
1231 pszEnv = _tgetenv(_T("NXAGENTD_CONFIG_D"));
1232 if (pszEnv != NULL)
1233 nx_strncpy(g_szConfigIncludeDir, pszEnv, MAX_PATH);
1234#endif
1235
5039dede
AK
1236 // Parse command line
1237 if (argc == 1)
1238 iAction = ACTION_HELP;
1239 opterr = 1;
1240 while((ch = getopt(argc, argv, VALID_OPTIONS)) != -1)
1241 {
1242 switch(ch)
1243 {
1244 case 'h': // Display help and exit
1245 iAction = ACTION_HELP;
1246 break;
f918b160
VK
1247 case 'K': // Shutdown external sub-agents
1248 iAction = ACTION_SHUTDOWN_EXT_AGENTS;
1249 break;
5039dede
AK
1250 case 'd': // Run as daemon
1251 g_dwFlags |= AF_DAEMON;
1252 break;
1253 case 'f': // Run in foreground
1254 g_dwFlags &= ~AF_DAEMON;
1255 break;
1256 case 'D': // Turn on debug output
53c96e2d
VK
1257 g_debugLevel = strtoul(optarg, &eptr, 0);
1258 if ((*eptr != 0) || (g_debugLevel > 9))
c303351c
VK
1259 {
1260 fprintf(stderr, "Invalid debug level: %s\n", optarg);
1261 iAction = -1;
1262 iExitCode = 1;
1263 }
5039dede
AK
1264 break;
1265 case 'c': // Configuration file
f3387429
VK
1266#ifdef UNICODE
1267 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szConfigFile, MAX_PATH);
1268 g_szConfigFile[MAX_PATH - 1] = 0;
1269#else
5039dede 1270 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
f3387429 1271#endif
5039dede 1272 break;
968031d9 1273#if !defined(_WIN32)
5039dede 1274 case 'p': // PID file
f3387429
VK
1275#ifdef UNICODE
1276 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szPidFile, MAX_PATH);
1277 g_szPidFile[MAX_PATH - 1] = 0;
1278#else
5039dede 1279 nx_strncpy(g_szPidFile, optarg, MAX_PATH);
f3387429 1280#endif
5039dede
AK
1281 break;
1282#endif
1283 case 'C': // Configuration check only
1284 iAction = ACTION_CHECK_CONFIG;
1285 break;
1286 case 'v': // Print version and exit
8e17001f 1287 _tprintf(_T("NetXMS Core Agent Version ") AGENT_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING IS_UNICODE_BUILD_STRING _T("\n"));
5039dede
AK
1288 iAction = ACTION_NONE;
1289 break;
1290 case 'M':
1291 g_dwFlags |= AF_CENTRAL_CONFIG;
f3387429
VK
1292#ifdef UNICODE
1293 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szConfigServer, MAX_DB_STRING);
1294 g_szConfigServer[MAX_DB_STRING - 1] = 0;
1295#else
5039dede 1296 nx_strncpy(g_szConfigServer, optarg, MAX_DB_STRING);
f3387429 1297#endif
5039dede
AK
1298 break;
1299 case 'r':
1300 g_dwFlags |= AF_REGISTER;
f3387429
VK
1301#ifdef UNICODE
1302 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szRegistrar, MAX_DB_STRING);
1303 g_szRegistrar[MAX_DB_STRING - 1] = 0;
1304#else
5039dede 1305 nx_strncpy(g_szRegistrar, optarg, MAX_DB_STRING);
f3387429 1306#endif
5039dede
AK
1307 break;
1308 case 'P': // Platform suffix
f3387429
VK
1309#ifdef UNICODE
1310 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szPlatformSuffix, MAX_PSUFFIX_LENGTH);
1311 g_szPlatformSuffix[MAX_PSUFFIX_LENGTH - 1] = 0;
1312#else
5039dede 1313 nx_strncpy(g_szPlatformSuffix, optarg, MAX_PSUFFIX_LENGTH);
f3387429 1314#endif
5039dede
AK
1315 break;
1316 case 'X': // Agent is being restarted
1317 bRestart = TRUE;
1318 dwOldPID = strtoul(optarg, NULL, 10);
1319 break;
9fcdfda7
VK
1320 case 'W': // Watchdog process
1321 iAction = ACTION_RUN_WATCHDOG;
1322 dwMainPID = strtoul(optarg, NULL, 10);
1323 break;
5039dede
AK
1324 case 'Z': // Create configuration file
1325 iAction = ACTION_CREATE_CONFIG;
f3387429
VK
1326#ifdef UNICODE
1327 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szConfigFile, MAX_PATH);
1328 g_szConfigFile[MAX_PATH - 1] = 0;
1329#else
5039dede 1330 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
f3387429 1331#endif
5039dede
AK
1332 break;
1333#ifdef _WIN32
1334 case 'H': // Hide window
1335 g_dwFlags |= AF_HIDE_WINDOW;
1336 break;
175bd003
VK
1337 case 'i':
1338 g_dwFlags |= AF_INTERACTIVE_SERVICE;
1339 break;
5039dede
AK
1340 case 'I': // Install Windows service
1341 iAction = ACTION_INSTALL_SERVICE;
1342 break;
1343 case 'R': // Remove Windows service
1344 iAction = ACTION_REMOVE_SERVICE;
1345 break;
1346 case 's': // Start Windows service
1347 iAction = ACTION_START_SERVICE;
1348 break;
1349 case 'S': // Stop Windows service
1350 iAction = ACTION_STOP_SERVICE;
1351 break;
1352 case 'E': // Install Windows event source
1353 iAction = ACTION_INSTALL_EVENT_SOURCE;
1354 break;
1355 case 'U': // Remove Windows event source
1356 iAction = ACTION_REMOVE_EVENT_SOURCE;
1357 break;
9f96fc88 1358 case 'e': // Event source name
7ee7f8bc
VK
1359#ifdef UNICODE
1360 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_windowsEventSourceName, MAX_PATH);
1361 g_windowsEventSourceName[MAX_PATH - 1] = 0;
1362#else
9f96fc88 1363 nx_strncpy(g_windowsEventSourceName, optarg, MAX_PATH);
7ee7f8bc 1364#endif
9f96fc88
VK
1365 break;
1366 case 'n': // Service name
7ee7f8bc
VK
1367#ifdef UNICODE
1368 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_windowsServiceName, MAX_PATH);
1369 g_windowsServiceName[MAX_PATH - 1] = 0;
1370#else
9f96fc88 1371 nx_strncpy(g_windowsServiceName, optarg, MAX_PATH);
7ee7f8bc 1372#endif
9f96fc88
VK
1373 break;
1374 case 'N': // Service display name
f3387429
VK
1375#ifdef UNICODE
1376 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_windowsServiceDisplayName, MAX_PATH);
1377 g_windowsServiceDisplayName[MAX_PATH - 1] = 0;
1378#else
9f96fc88 1379 nx_strncpy(g_windowsServiceDisplayName, optarg, MAX_PATH);
f3387429 1380#endif
9f96fc88 1381 break;
5039dede
AK
1382#endif
1383 case '?':
1384 iAction = ACTION_HELP;
1385 iExitCode = 1;
1386 break;
1387 default:
1388 break;
1389 }
1390 }
1391
968031d9 1392#if !defined(_WIN32)
5039dede
AK
1393 if (!_tcscmp(g_szConfigFile, _T("{search}")))
1394 {
f31c22b3
VK
1395 TCHAR path[MAX_PATH] = _T("");
1396 const TCHAR *homeDir = _tgetenv(_T("NETXMS_HOME"));
1397 if (homeDir != NULL)
1398 {
1399 _sntprintf(path, MAX_PATH, _T("%s/etc/nxagentd.conf"), homeDir);
1400 }
1401 if ((path[0] != 0) && (_taccess(path, 4) == 0))
1402 {
1403 _tcscpy(g_szConfigFile, path);
1404 }
1405 else if (_taccess(PREFIX _T("/etc/nxagentd.conf"), 4) == 0)
5039dede 1406 {
f3387429 1407 _tcscpy(g_szConfigFile, PREFIX _T("/etc/nxagentd.conf"));
5039dede 1408 }
a1716ea0
VK
1409 else if (_taccess(_T("/Database/etc/nxagentd.conf"), 4) == 0) // for ZeroShell
1410 {
1411 _tcscpy(g_szConfigFile, _T("/Database/etc/nxagentd.conf"));
1412 }
f3387429 1413 else if (_taccess(_T("/usr/etc/nxagentd.conf"), 4) == 0)
5039dede 1414 {
f3387429 1415 _tcscpy(g_szConfigFile, _T("/usr/etc/nxagentd.conf"));
5039dede
AK
1416 }
1417 else
1418 {
f3387429 1419 _tcscpy(g_szConfigFile, _T("/etc/nxagentd.conf"));
5039dede
AK
1420 }
1421 }
80ce37ac 1422 if (!_tcscmp(g_szConfigIncludeDir, _T("{search}")))
abf35d58 1423 {
f31c22b3
VK
1424 TCHAR path[MAX_PATH] = _T("");
1425 const TCHAR *homeDir = _tgetenv(_T("NETXMS_HOME"));
1426 if (homeDir != NULL)
1427 {
1428 _sntprintf(path, MAX_PATH, _T("%s/etc/nxagentd.conf.d"), homeDir);
1429 }
1430 if ((path[0] != 0) && (_taccess(path, 4) == 0))
1431 {
1432 _tcscpy(g_szConfigIncludeDir, path);
1433 }
1434 else if (_taccess(PREFIX _T("/etc/nxagentd.conf.d"), 4) == 0)
abf35d58 1435 {
f3387429 1436 _tcscpy(g_szConfigIncludeDir, PREFIX _T("/etc/nxagentd.conf.d"));
abf35d58 1437 }
a1716ea0
VK
1438 else if (_taccess(_T("/Database/etc/nxagentd.conf.d"), 4) == 0)
1439 {
1440 _tcscpy(g_szConfigIncludeDir, _T("/Database/etc/nxagentd.conf.d"));
1441 }
f3387429 1442 else if (_taccess(_T("/usr/etc/nxagentd.conf.d"), 4) == 0)
abf35d58 1443 {
f3387429 1444 _tcscpy(g_szConfigIncludeDir, _T("/usr/etc/nxagentd.conf.d"));
abf35d58
VK
1445 }
1446 else
1447 {
f3387429 1448 _tcscpy(g_szConfigIncludeDir, _T("/etc/nxagentd.conf.d"));
abf35d58
VK
1449 }
1450 }
5039dede
AK
1451#endif
1452
1453 if (bRestart)
1454 DoRestartActions(dwOldPID);
1455
a1716ea0 1456 InitConfig();
e6c91aac 1457
5039dede
AK
1458 // Do requested action
1459 switch(iAction)
1460 {
1461 case ACTION_RUN_AGENT:
1462 // Set default value for session idle timeout based on
1463 // connect() timeout, if possible
1464#if HAVE_SYSCTLBYNAME && !defined(_IPSO)
1465 {
1466 LONG nVal;
1467 size_t nSize;
1468
1469 nSize = sizeof(nVal);
1470 if (sysctlbyname("net.inet.tcp.keepinit", &nVal, &nSize, NULL, 0) == 0)
1471 {
1472 g_dwIdleTimeout = nVal / 1000 + 15;
1473 }
1474 }
1475#endif
1476
1477 if (g_dwFlags & AF_CENTRAL_CONFIG)
1478 {
c303351c 1479 if (g_debugLevel > 0)
f3387429 1480 _tprintf(_T("Downloading configuration from %s...\n"), g_szConfigServer);
5039dede
AK
1481 if (DownloadConfig(g_szConfigServer))
1482 {
c303351c 1483 if (g_debugLevel > 0)
f3387429 1484 _tprintf(_T("Configuration downloaded successfully\n"));
5039dede
AK
1485 }
1486 else
1487 {
c303351c 1488 if (g_debugLevel > 0)
f3387429 1489 _tprintf(_T("Configuration download failed\n"));
5039dede
AK
1490 }
1491 }
1492
abf35d58 1493 if (g_config->loadConfig(g_szConfigFile, _T("agent")))
e6c91aac 1494 {
357a2954
AK
1495 const TCHAR *dir = g_config->getValue(_T("/agent/ConfigIncludeDir"));
1496 if (dir != NULL)
6ca3b41c
VK
1497 nx_strncpy(g_szConfigIncludeDir, dir, MAX_PATH);
1498 g_config->loadConfigDirectory(g_szConfigIncludeDir, _T("agent"));
abf35d58
VK
1499 if (g_config->parseTemplate(_T("agent"), m_cfgTemplate))
1500 {
2b58ee20
AK
1501 if (g_szEncryptedSharedSecret[0] != 0)
1502 {
1503 DecryptPassword(_T("netxms"), g_szEncryptedSharedSecret, g_szSharedSecret);
1504 }
1505
134c8b79
AK
1506 // try to guess executable path
1507#ifdef _WIN32
5a0d14cf 1508 GetModuleFileName(GetModuleHandle(NULL), s_executableName, MAX_PATH);
134c8b79
AK
1509#else
1510#ifdef UNICODE
1511 char __buffer[PATH_MAX];
1512#else
5a0d14cf 1513#define __buffer s_executableName
134c8b79
AK
1514#endif
1515 if (realpath(argv[0], __buffer) == NULL)
1516 {
1517 // fallback
5a0d14cf 1518 nx_strncpy(s_executableName, PREFIX _T("/bin/nxagentd"), sizeof(s_executableName) / sizeof(s_executableName[0]));
134c8b79
AK
1519 }
1520 else
1521 {
1522#ifdef UNICODE
1523 int len = strlen(__buffer);
5a0d14cf 1524 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, __buffer, len, s_executableName, len);
134c8b79
AK
1525#endif
1526 }
1527#endif
1528
0bbab9d3 1529 // Set exception handler
9fcdfda7 1530#ifdef _WIN32
abf35d58
VK
1531 if (g_dwFlags & AF_CATCH_EXCEPTIONS)
1532 SetExceptionHandler(SEHServiceExceptionHandler, SEHServiceExceptionDataWriter, m_szDumpDir,
bf3b7f79 1533 _T("nxagentd"), MSG_EXCEPTION, g_dwFlags & AF_WRITE_FULL_DUMP, !(g_dwFlags & AF_DAEMON));
abf35d58 1534 __try {
9fcdfda7 1535#endif
cc022855 1536 if ((!_tcsicmp(g_szLogFile, _T("{syslog}"))) ||
bf3b7f79 1537 (!_tcsicmp(g_szLogFile, _T("{eventlog}"))))
abf35d58 1538 g_dwFlags |= AF_USE_SYSLOG;
5039dede
AK
1539
1540#ifdef _WIN32
abf35d58
VK
1541 if (g_dwFlags & AF_DAEMON)
1542 {
1543 InitService();
1544 }
1545 else
1546 {
1547 if (Initialize())
1548 {
1549 Main();
1550 }
1551 else
1552 {
bf3b7f79 1553 ConsolePrintf(_T("Agent initialization failed\n"));
abf35d58
VK
1554 nxlog_close();
1555 iExitCode = 3;
1556 }
1557 }
5039dede 1558#else /* _WIN32 */
abf35d58 1559 if (g_dwFlags & AF_DAEMON)
f31c22b3 1560 {
abf35d58
VK
1561 if (daemon(0, 0) == -1)
1562 {
1563 perror("Unable to setup itself as a daemon");
1564 iExitCode = 4;
1565 }
f31c22b3 1566 }
abf35d58 1567 if (iExitCode == 0)
f31c22b3 1568 {
abf35d58 1569 m_pid = getpid();
abf35d58
VK
1570 if (Initialize())
1571 {
abf35d58
VK
1572 FILE *fp;
1573
1574 // Write PID file
f3387429 1575 fp = _tfopen(g_szPidFile, _T("w"));
abf35d58
VK
1576 if (fp != NULL)
1577 {
f3387429 1578 _ftprintf(fp, _T("%d"), m_pid);
abf35d58 1579 fclose(fp);
cc022855 1580 }
abf35d58
VK
1581 Main();
1582 Shutdown();
1583 }
1584 else
1585 {
bf3b7f79 1586 ConsolePrintf(_T("Agent initialization failed\n"));
abf35d58
VK
1587 nxlog_close();
1588 iExitCode = 3;
1589 }
1590 }
5039dede
AK
1591#endif /* _WIN32 */
1592
968031d9 1593#if defined(_WIN32)
abf35d58
VK
1594 if (m_hCondShutdown != INVALID_CONDITION_HANDLE)
1595 ConditionDestroy(m_hCondShutdown);
9fcdfda7
VK
1596#endif
1597#ifdef _WIN32
abf35d58 1598 LIBNETXMS_EXCEPTION_HANDLER
5039dede 1599#endif
abf35d58
VK
1600 }
1601 else
1602 {
bf3b7f79 1603 ConsolePrintf(_T("Error parsing configuration file\n"));
abf35d58
VK
1604 iExitCode = 2;
1605 }
5039dede
AK
1606 }
1607 else
1608 {
bf3b7f79 1609 ConsolePrintf(_T("Error loading configuration file\n"));
5039dede
AK
1610 iExitCode = 2;
1611 }
1612 break;
1613 case ACTION_CHECK_CONFIG:
5039dede 1614 {
31e21b08
AK
1615 bool validConfig = g_config->loadConfig(g_szConfigFile, _T("agent"), false);
1616 if (validConfig)
1617 {
1618 const TCHAR *dir = g_config->getValue(_T("/agent/ConfigIncludeDir"));
1619 if (dir != NULL)
1620 {
99877e7b
VK
1621 validConfig = g_config->loadConfigDirectory(dir, _T("agent"), false);
1622 ConsolePrintf(_T("Error reading additional configuration files from \"%s\"\n"), dir);
31e21b08
AK
1623 }
1624 }
1625
1626 if (validConfig)
1627 {
1628 validConfig = g_config->parseTemplate(_T("agent"), m_cfgTemplate);
1629 }
1630
1631 if (!validConfig)
1632 {
1633 ConsolePrintf(_T("Configuration file check failed\n"));
1634 iExitCode = 2;
1635 }
5039dede
AK
1636 }
1637 break;
9fcdfda7
VK
1638 case ACTION_RUN_WATCHDOG:
1639 iExitCode = WatchdogMain(dwMainPID);
1640 break;
5039dede 1641 case ACTION_CREATE_CONFIG:
f3387429
VK
1642 iExitCode = CreateConfig(CHECK_NULL_A(argv[optind]), CHECK_NULL_A(argv[optind + 1]),
1643 CHECK_NULL_A(argv[optind + 2]), CHECK_NULL_A(argv[optind + 3]),
1644 argc - optind - 4, &argv[optind + 4]);
5039dede 1645 break;
f918b160
VK
1646 case ACTION_SHUTDOWN_EXT_AGENTS:
1647 InitiateExtSubagentShutdown();
1648 iExitCode = 0;
1649 break;
5039dede
AK
1650#ifdef _WIN32
1651 case ACTION_INSTALL_SERVICE:
1652 GetModuleFileName(GetModuleHandle(NULL), szModuleName, MAX_PATH);
1653 InstallService(szModuleName, g_szConfigFile);
1654 break;
1655 case ACTION_REMOVE_SERVICE:
1656 RemoveService();
1657 break;
1658 case ACTION_INSTALL_EVENT_SOURCE:
1659 GetModuleFileName(GetModuleHandle(NULL), szModuleName, MAX_PATH);
1660 InstallEventSource(szModuleName);
1661 break;
1662 case ACTION_REMOVE_EVENT_SOURCE:
1663 RemoveEventSource();
1664 break;
1665 case ACTION_START_SERVICE:
1666 StartAgentService();
1667 break;
1668 case ACTION_STOP_SERVICE:
1669 StopAgentService();
1670 break;
1671#endif
1672 case ACTION_HELP:
f3387429 1673 _fputts(m_szHelpText, stdout);
5039dede
AK
1674 break;
1675 default:
1676 break;
1677 }
1678
5039dede
AK
1679 return iExitCode;
1680}