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