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