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