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