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