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