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