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