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