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