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