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