fixed C API incompatibility with current protocol version
[public/netxms.git] / src / agent / core / nxagentd.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS multiplatform core agent
0bd64860 3** Copyright (C) 2003-2012 Victor Kirhenshtein
5039dede
AK
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**
f0c1d2a4
AK
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
5039dede
AK
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"
b34606f7 24#include <nxdbapi.h>
5039dede
AK
25
26#if defined(_WIN32)
27#include <conio.h>
28#include <locale.h>
29#elif defined(_NETWARE)
30#include <screen.h>
31#include <library.h>
32#else
33#include <signal.h>
34#include <sys/wait.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
46//
47// Externals
48//
49
50THREAD_RESULT THREAD_CALL ListenerThread(void *);
51THREAD_RESULT THREAD_CALL SessionWatchdog(void *);
52THREAD_RESULT THREAD_CALL TrapSender(void *);
0df58041 53THREAD_RESULT THREAD_CALL MasterAgentListener(void *arg);
5039dede
AK
54
55void ShutdownTrapSender();
56
9fcdfda7
VK
57void StartWatchdog();
58void StopWatchdog();
59int WatchdogMain(DWORD pid);
60
6aab2983
AK
61void InitSessionList();
62
5039dede 63#if !defined(_WIN32) && !defined(_NETWARE)
203e9d8a 64void InitStaticSubagents();
5039dede
AK
65#endif
66
9f96fc88
VK
67#ifdef _WIN32
68extern TCHAR g_windowsServiceName[];
69extern TCHAR g_windowsServiceDisplayName[];
70#endif
71
5039dede
AK
72
73//
74// Messages generated by mc.pl (for UNIX version only)
75//
76
77#ifndef _WIN32
78extern unsigned int g_dwNumMessages;
79extern const TCHAR *g_szMessages[];
80#endif
81
82
83//
84// Valid options for getopt()
85//
86
87#if defined(_WIN32)
175bd003 88#define VALID_OPTIONS "c:CdD:e:EfhHiIM:n:N:P:r:RsSUvX:W:Z:"
5039dede 89#elif defined(_NETWARE)
c303351c 90#define VALID_OPTIONS "c:CD:fhM:P:r:vZ:"
5039dede 91#else
c303351c 92#define VALID_OPTIONS "c:CdD:fhM:p:P:r:vX:W:Z:"
5039dede
AK
93#endif
94
95
96//
97// Actions
98//
99
100#define ACTION_NONE 0
101#define ACTION_RUN_AGENT 1
102#define ACTION_INSTALL_SERVICE 2
103#define ACTION_REMOVE_SERVICE 3
104#define ACTION_START_SERVICE 4
105#define ACTION_STOP_SERVICE 5
106#define ACTION_CHECK_CONFIG 6
107#define ACTION_INSTALL_EVENT_SOURCE 7
108#define ACTION_REMOVE_EVENT_SOURCE 8
109#define ACTION_CREATE_CONFIG 9
110#define ACTION_HELP 10
9fcdfda7 111#define ACTION_RUN_WATCHDOG 11
5039dede
AK
112
113
114//
115// Global variables
116//
117
118DWORD g_dwFlags = AF_ENABLE_ACTIONS | AF_ENABLE_AUTOLOAD;
bf3b7f79
VK
119TCHAR g_szLogFile[MAX_PATH] = AGENT_DEFAULT_LOG;
120TCHAR g_szSharedSecret[MAX_SECRET_LENGTH] = _T("admin");
121TCHAR g_szConfigFile[MAX_PATH] = AGENT_DEFAULT_CONFIG;
122TCHAR g_szFileStore[MAX_PATH] = AGENT_DEFAULT_FILE_STORE;
123TCHAR g_szDataDirectory[MAX_PATH] = AGENT_DEFAULT_DATA_DIR;
124TCHAR g_szPlatformSuffix[MAX_PSUFFIX_LENGTH] = _T("");
125TCHAR g_szConfigServer[MAX_DB_STRING] = _T("not_set");
126TCHAR g_szRegistrar[MAX_DB_STRING] = _T("not_set");
127TCHAR g_szListenAddress[MAX_PATH] = _T("*");
6ca3b41c 128TCHAR g_szConfigIncludeDir[MAX_PATH] = AGENT_DEFAULT_CONFIG_D;
0df58041 129TCHAR g_masterAgent[MAX_PATH] = _T("not_set");
5039dede
AK
130WORD g_wListenPort = AGENT_LISTEN_PORT;
131SERVER_INFO g_pServerList[MAX_SERVERS];
132DWORD g_dwServerCount = 0;
133DWORD g_dwExecTimeout = 2000; // External process execution timeout in milliseconds
134DWORD g_dwSNMPTimeout = 3000;
135time_t g_tmAgentStartTime;
136DWORD g_dwStartupDelay = 0;
137DWORD g_dwMaxSessions = 32;
15e11d1b 138DWORD g_debugLevel = 0;
e6c91aac 139Config *g_config;
5039dede
AK
140#ifdef _WIN32
141DWORD g_dwIdleTimeout = 60; // Session idle timeout
142#else
143DWORD g_dwIdleTimeout = 120; // Session idle timeout
144#endif
145
146#if !defined(_WIN32) && !defined(_NETWARE)
bf3b7f79 147TCHAR g_szPidFile[MAX_PATH] = _T("/var/run/nxagentd.pid");
5039dede
AK
148#endif
149
150#ifdef _WIN32
5039dede
AK
151DWORD (__stdcall *imp_HrLanConnectionNameFromGuidOrPath)(LPWSTR, LPWSTR, LPWSTR, LPDWORD);
152#endif /* _WIN32 */
153
154#ifdef _NETWARE
155int g_nThreadCount = 0;
156#endif
157
158
159//
160// Static variables
161//
162
bf3b7f79
VK
163static TCHAR *m_pszActionList = NULL;
164static TCHAR *m_pszShellActionList = NULL;
165static TCHAR *m_pszServerList = NULL;
166static TCHAR *m_pszControlServerList = NULL;
167static TCHAR *m_pszMasterServerList = NULL;
168static TCHAR *m_pszSubagentList = NULL;
169static TCHAR *m_pszExtParamList = NULL;
170static TCHAR *m_pszShExtParamList = NULL;
9795113c 171static TCHAR *m_pszParamProviderList = NULL;
204ace22 172static TCHAR *m_pszExtSubagentList = NULL;
5039dede
AK
173static DWORD m_dwEnabledCiphers = 0xFFFF;
174static THREAD m_thSessionWatchdog = INVALID_THREAD_HANDLE;
175static THREAD m_thListener = INVALID_THREAD_HANDLE;
176static THREAD m_thTrapSender = INVALID_THREAD_HANDLE;
0df58041 177static THREAD m_thMasterAgentListener = INVALID_THREAD_HANDLE;
bf3b7f79
VK
178static TCHAR m_szProcessToWait[MAX_PATH] = _T("");
179static TCHAR m_szDumpDir[MAX_PATH] = _T("C:\\");
4addc3a3
VK
180static DWORD m_dwMaxLogSize = 16384 * 1024;
181static DWORD m_dwLogHistorySize = 4;
5945d50a
VK
182static DWORD m_dwLogRotationMode = NXLOG_ROTATION_BY_SIZE;
183static TCHAR m_szDailyLogFileSuffix[64] = _T("");
203e9d8a 184static Config *s_registry = NULL;
5039dede
AK
185
186#if defined(_WIN32) || defined(_NETWARE)
187static CONDITION m_hCondShutdown = INVALID_CONDITION_HANDLE;
188#endif
189
190#if !defined(_WIN32) && !defined(_NETWARE)
191static pid_t m_pid;
192#endif
193
194
195//
196// Configuration file template
197//
198
199static NX_CFG_TEMPLATE m_cfgTemplate[] =
200{
201 { "Action", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszActionList },
202 { "ActionShellExec", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszShellActionList },
203 { "ControlServers", CT_STRING_LIST, ',', 0, 0, 0, &m_pszControlServerList },
9fcdfda7 204 { "CreateCrashDumps", CT_BOOLEAN, 0, 0, AF_CATCH_EXCEPTIONS, 0, &g_dwFlags },
203e9d8a 205 { "DataDirectory", CT_STRING, 0, 0, MAX_PATH, 0, g_szDataDirectory },
5945d50a 206 { "DailyLogFileSuffix", CT_STRING, 0, 0, MAX_PATH, 0, m_szDailyLogFileSuffix },
15e11d1b 207 { "DebugLevel", CT_LONG, 0, 0, 0, 0, &g_debugLevel },
9fcdfda7 208 { "DumpDirectory", CT_STRING, 0, 0, MAX_PATH, 0, m_szDumpDir },
5039dede 209 { "EnableActions", CT_BOOLEAN, 0, 0, AF_ENABLE_ACTIONS, 0, &g_dwFlags },
1a5e0c22 210 { "EnableArbitraryFileUpload", CT_BOOLEAN, 0, 0, AF_ARBITRARY_FILE_UPLOAD, 0, &g_dwFlags },
5039dede
AK
211 { "EnabledCiphers", CT_LONG, 0, 0, 0, 0, &m_dwEnabledCiphers },
212 { "EnableProxy", CT_BOOLEAN, 0, 0, AF_ENABLE_PROXY, 0, &g_dwFlags },
213 { "EnableSNMPProxy", CT_BOOLEAN, 0, 0, AF_ENABLE_SNMP_PROXY, 0, &g_dwFlags },
214 { "EnableSubagentAutoload", CT_BOOLEAN, 0, 0, AF_ENABLE_AUTOLOAD, 0, &g_dwFlags },
9fcdfda7 215 { "EnableWatchdog", CT_BOOLEAN, 0, 0, AF_ENABLE_WATCHDOG, 0, &g_dwFlags },
5039dede 216 { "ExecTimeout", CT_LONG, 0, 0, 0, 0, &g_dwExecTimeout },
0df58041 217 { "ExternalMasterAgent", CT_STRING, 0, 0, MAX_PATH, 0, g_masterAgent },
5039dede
AK
218 { "ExternalParameter", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszExtParamList },
219 { "ExternalParameterShellExec", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszShExtParamList },
9795113c 220 { "ExternalParametersProvider", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszParamProviderList },
204ace22 221 { "ExternalSubagent", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszExtSubagentList },
5039dede 222 { "FileStore", CT_STRING, 0, 0, MAX_PATH, 0, g_szFileStore },
cbc777ee 223 { "FullCrashDumps", CT_BOOLEAN, 0, 0, AF_WRITE_FULL_DUMP, 0, &g_dwFlags },
5039dede
AK
224 { "ListenAddress", CT_STRING, 0, 0, MAX_PATH, 0, g_szListenAddress },
225 { "ListenPort", CT_WORD, 0, 0, 0, 0, &g_wListenPort },
226 { "LogFile", CT_STRING, 0, 0, MAX_PATH, 0, g_szLogFile },
4addc3a3 227 { "LogHistorySize", CT_LONG, 0, 0, 0, 0, &m_dwLogHistorySize },
5945d50a 228 { "LogRotationMode", CT_LONG, 0, 0, 0, 0, &m_dwLogRotationMode },
5039dede
AK
229 { "LogUnresolvedSymbols", CT_BOOLEAN, 0, 0, AF_LOG_UNRESOLVED_SYMBOLS, 0, &g_dwFlags },
230 { "MasterServers", CT_STRING_LIST, ',', 0, 0, 0, &m_pszMasterServerList },
4addc3a3 231 { "MaxLogSize", CT_LONG, 0, 0, 0, 0, &m_dwMaxLogSize },
5039dede
AK
232 { "MaxSessions", CT_LONG, 0, 0, 0, 0, &g_dwMaxSessions },
233 { "PlatformSuffix", CT_STRING, 0, 0, MAX_PSUFFIX_LENGTH, 0, g_szPlatformSuffix },
234 { "RequireAuthentication", CT_BOOLEAN, 0, 0, AF_REQUIRE_AUTH, 0, &g_dwFlags },
235 { "RequireEncryption", CT_BOOLEAN, 0, 0, AF_REQUIRE_ENCRYPTION, 0, &g_dwFlags },
236 { "Servers", CT_STRING_LIST, ',', 0, 0, 0, &m_pszServerList },
237 { "SessionIdleTimeout", CT_LONG, 0, 0, 0, 0, &g_dwIdleTimeout },
238 { "SharedSecret", CT_STRING, 0, 0, MAX_SECRET_LENGTH, 0, g_szSharedSecret },
239 { "StartupDelay", CT_LONG, 0, 0, 0, 0, &g_dwStartupDelay },
240 { "SubAgent", CT_STRING_LIST, '\n', 0, 0, 0, &m_pszSubagentList },
241 { "TimeOut", CT_IGNORE, 0, 0, 0, 0, NULL },
242 { "WaitForProcess", CT_STRING, 0, 0, MAX_PATH, 0, m_szProcessToWait },
243 { "", CT_END_OF_LIST, 0, 0, 0, 0, NULL }
244};
245
246
247//
248// Help text
249//
250
251static char m_szHelpText[] =
252 "Usage: nxagentd [options]\n"
253 "Where valid options are:\n"
254 " -c <file> : Use configuration file <file> (default " AGENT_DEFAULT_CONFIG ")\n"
255 " -C : Check configuration file and exit\n"
256#ifndef _NETWARE
257 " -d : Run as daemon/service\n"
258#endif
c303351c 259 " -D <level> : Set debug level (0..9)\n"
9f96fc88
VK
260#ifdef _WIN32
261 " -e <name> : Windows event source name\n"
262#endif
5039dede
AK
263 " -f : Run in foreground\n"
264 " -h : Display help and exit\n"
265#ifdef _WIN32
266 " -H : Hide agent's window when in standalone mode\n"
175bd003 267 " -i : Installed Windows service must be interactive\n"
5039dede
AK
268 " -I : Install Windows service\n"
269#endif
270 " -M <addr> : Download config from management server <addr>\n"
9f96fc88
VK
271#ifdef _WIN32
272 " -n <name> : Service name\n"
273 " -N <name> : Service display name\n"
274#endif
5039dede
AK
275#if !defined(_WIN32) && !defined(_NETWARE)
276 " -p : Path to pid file (default: /var/run/nxagentd.pid)\n"
277#endif
278 " -P <text> : Set platform suffix to <text>\n"
279 " -r <addr> : Register agent on management server <addr>\n"
280#ifdef _WIN32
281 " -R : Remove Windows service\n"
282 " -s : Start Windows servive\n"
283 " -S : Stop Windows service\n"
284#endif
285 " -v : Display version and exit\n"
286 "\n";
287
288
203e9d8a
VK
289//
290// Save registry
291//
292
293static void SaveRegistry()
294{
295 TCHAR regPath[MAX_PATH];
296 nx_strncpy(regPath, g_szDataDirectory, MAX_PATH - _tcslen(REGISTRY_FILE_NAME) - 1);
297 if (regPath[_tcslen(regPath) - 1] != FS_PATH_SEPARATOR_CHAR)
298 _tcscat(regPath, FS_PATH_SEPARATOR);
299 _tcscat(regPath, REGISTRY_FILE_NAME);
300
301 String xml = s_registry->createXml();
302 FILE *f = _tfopen(regPath, _T("w"));
303 if (f != NULL)
304 {
305 _fputts((const TCHAR *)xml, f);
306 fclose(f);
307 }
308 else
309 {
310 nxlog_write(MSG_REGISTRY_SAVE_FAILED, NXLOG_ERROR, "ss", regPath, strerror(errno));
311 }
312}
313
314
315//
316// Open registry
317//
318
319Config *OpenRegistry()
320{
321 s_registry->lock();
322 return s_registry;
323}
324
325
326//
327// Close registry
328//
329
330void CloseRegistry(bool modified)
331{
332 if (modified)
333 SaveRegistry();
334 s_registry->unlock();
335}
336
337
5039dede
AK
338#ifdef _WIN32
339
340//
341// Get our own console window handle (an alternative to Microsoft's GetConsoleWindow)
342//
343
203e9d8a 344static HWND GetConsoleHWND()
5039dede
AK
345{
346 HWND hWnd;
347 DWORD wpid, cpid;
348
349 cpid = GetCurrentProcessId();
350 while(1)
351 {
352 hWnd = FindWindowEx(NULL, NULL, _T("ConsoleWindowClass"), NULL);
353 if (hWnd == NULL)
354 break;
355
356 GetWindowThreadProcessId(hWnd, &wpid);
357 if (cpid == wpid)
358 break;
359 }
360
361 return hWnd;
362}
363
364
365//
366// Get proc address and write log file
367//
368
369static FARPROC GetProcAddressAndLog(HMODULE hModule, LPCSTR procName)
370{
371 FARPROC ptr;
372
373 ptr = GetProcAddress(hModule, procName);
374 if ((ptr == NULL) && (g_dwFlags & AF_LOG_UNRESOLVED_SYMBOLS))
375 nxlog_write(MSG_NO_FUNCTION, EVENTLOG_WARNING_TYPE, "s", procName);
376 return ptr;
377}
378
379
380//
381// Import symbols
382//
383
203e9d8a 384static void ImportSymbols()
5039dede
AK
385{
386 HMODULE hModule;
387
5039dede 388 // NETMAN.DLL
bf3b7f79 389 hModule = LoadLibrary(_T("NETMAN.DLL"));
5039dede
AK
390 if (hModule != NULL)
391 {
392 imp_HrLanConnectionNameFromGuidOrPath =
393 (DWORD (__stdcall *)(LPWSTR, LPWSTR, LPWSTR, LPDWORD))GetProcAddressAndLog(hModule,
394 "HrLanConnectionNameFromGuidOrPath");
395 }
396 else
397 {
398 nxlog_write(MSG_NO_DLL, EVENTLOG_WARNING_TYPE, "s", "NETMAN.DLL");
399 }
400}
401
402
403//
404// Shutdown thread (created by H_RestartAgent)
405//
406
407static THREAD_RESULT THREAD_CALL ShutdownThread(void *pArg)
408{
8e954797 409 DebugPrintf(INVALID_INDEX, 1, _T("Shutdown thread started"));
5039dede
AK
410 Shutdown();
411 ExitProcess(0);
412 return THREAD_OK; // Never reached
413}
414
415#endif /* _WIN32 */
416
417
418//
419// Restart agent
420//
421
6173bea8 422static LONG H_RestartAgent(const TCHAR *action, StringList *args, const TCHAR *data)
5039dede 423{
5b2c3e2d
VK
424 DebugPrintf(INVALID_INDEX, 1, _T("H_RestartAgent() called"));
425
5039dede
AK
426#ifdef _NETWARE
427 return ERR_NOT_IMPLEMENTED;
428#else
429 TCHAR szCmdLine[4096], szPlatformSuffixOption[MAX_PSUFFIX_LENGTH + 16];
430#ifdef _WIN32
431 TCHAR szExecName[MAX_PATH];
432 DWORD dwResult;
433 STARTUPINFO si;
434 PROCESS_INFORMATION pi;
435
436 GetModuleFileName(GetModuleHandle(NULL), szExecName, MAX_PATH);
437#else
438 TCHAR szExecName[MAX_PATH] = PREFIX _T("/bin/nxagentd");
439#endif
440
441 if (g_szPlatformSuffix[0] != 0)
442 {
443 _sntprintf(szPlatformSuffixOption, MAX_PSUFFIX_LENGTH + 16, _T("-P \"%s\" "), g_szPlatformSuffix);
444 }
445 else
446 {
447 szPlatformSuffixOption[0] = 0;
448 }
449
450#ifdef _WIN32
c303351c 451 _sntprintf(szCmdLine, 4096, _T("\"%s\" -c \"%s\" -n \"%s\" -e \"%s\" %s%s%s%s%s-D %d %s-X %u"), szExecName,
93599cfd
VK
452 g_szConfigFile, g_windowsServiceName, g_windowsEventSourceName,
453 (g_dwFlags & AF_DAEMON) ? _T("-d ") : _T(""),
5039dede
AK
454 (g_dwFlags & AF_HIDE_WINDOW) ? _T("-H ") : _T(""),
455 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T("-M ") : _T(""),
456 (g_dwFlags & AF_CENTRAL_CONFIG) ? g_szConfigServer : _T(""),
457 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T(" ") : _T(""),
c303351c 458 g_debugLevel, szPlatformSuffixOption,
5039dede 459 (g_dwFlags & AF_DAEMON) ? 0 : GetCurrentProcessId());
c303351c 460 DebugPrintf(INVALID_INDEX, 1, _T("Restarting agent with command line '%s'"), szCmdLine);
5039dede 461
5039dede
AK
462 // Fill in process startup info structure
463 memset(&si, 0, sizeof(STARTUPINFO));
464 si.cb = sizeof(STARTUPINFO);
465
466 // Create new process
467 if (!CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE,
468 (g_dwFlags & AF_DAEMON) ? (CREATE_NO_WINDOW | DETACHED_PROCESS) : (CREATE_NEW_CONSOLE),
469 NULL, NULL, &si, &pi))
470 {
471 nxlog_write(MSG_CREATE_PROCESS_FAILED, EVENTLOG_ERROR_TYPE, "se", szCmdLine, GetLastError());
472 dwResult = ERR_EXEC_FAILED;
473 }
474 else
475 {
476 // Close all handles
477 CloseHandle(pi.hThread);
478 CloseHandle(pi.hProcess);
479 dwResult = ERR_SUCCESS;
480 }
481 if ((dwResult == ERR_SUCCESS) && (!(g_dwFlags & AF_DAEMON)))
482 {
483 if (g_dwFlags & AF_HIDE_WINDOW)
484 {
485 ConditionSet(m_hCondShutdown);
486 }
487 else
488 {
489 ThreadCreate(ShutdownThread, 0, NULL);
490 }
491 }
492 return dwResult;
493#else
c303351c 494 _sntprintf(szCmdLine, 4096, _T("\"%s\" -c \"%s\" %s%s%s%s-D %d %s-X %lu"), szExecName,
5039dede
AK
495 g_szConfigFile, (g_dwFlags & AF_DAEMON) ? _T("-d ") : _T(""),
496 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T("-M ") : _T(""),
497 (g_dwFlags & AF_CENTRAL_CONFIG) ? g_szConfigServer : _T(""),
498 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T(" ") : _T(""),
53c96e2d 499 (int)g_debugLevel, szPlatformSuffixOption,
5039dede 500 (unsigned long)m_pid);
5b2c3e2d 501 DebugPrintf(INVALID_INDEX, 1, _T("Restarting agent with command line '%s'"), szCmdLine);
9fcdfda7 502 return ExecuteCommand(szCmdLine, NULL, NULL);
5039dede
AK
503#endif
504#endif /* _NETWARE */
505}
506
507
508//
509// This function writes message from subagent to agent's log
510//
511
c303351c 512static void WriteSubAgentMsg(int logLevel, int debugLevel, const TCHAR *pszMsg)
5039dede 513{
c303351c 514 if (logLevel == EVENTLOG_DEBUG_TYPE)
5039dede 515 {
15e11d1b 516 if (debugLevel <= (int)g_debugLevel)
c303351c 517 nxlog_write(MSG_DEBUG, EVENTLOG_DEBUG_TYPE, "s", pszMsg);
5039dede
AK
518 }
519 else
520 {
c303351c 521 nxlog_write(MSG_SUBAGENT_MSG, logLevel, "s", pszMsg);
5039dede
AK
522 }
523}
524
525
526//
527// Signal handler for UNIX platforms
528//
529
530#if !defined(_WIN32) && !defined(_NETWARE)
531
532static THREAD_RESULT THREAD_CALL SignalHandler(void *pArg)
533{
534 sigset_t signals;
535 int nSignal;
536
537 sigemptyset(&signals);
538 sigaddset(&signals, SIGTERM);
539 sigaddset(&signals, SIGINT);
540 sigaddset(&signals, SIGPIPE);
541 sigaddset(&signals, SIGSEGV);
542 sigaddset(&signals, SIGHUP);
543 sigaddset(&signals, SIGUSR1);
544 sigaddset(&signals, SIGUSR2);
545
546 sigprocmask(SIG_BLOCK, &signals, NULL);
547
548 while(1)
549 {
550 if (sigwait(&signals, &nSignal) == 0)
551 {
552 switch(nSignal)
553 {
554 case SIGTERM:
555 case SIGINT:
556 goto stop_handler;
557 case SIGSEGV:
558 abort();
559 break;
560 default:
561 break;
562 }
563 }
564 else
565 {
566 ThreadSleepMs(100);
567 }
568 }
569
570stop_handler:
571 sigprocmask(SIG_UNBLOCK, &signals, NULL);
572 return THREAD_OK;
573}
574
575#endif
576
577
578//
579// Load subagent for Windows NT or Windows 9x or platform subagent on UNIX
580//
581
582#ifdef _WIN32
583
203e9d8a 584void LoadWindowsSubagent()
5039dede
AK
585{
586 OSVERSIONINFO ver;
587
588 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
589 if (GetVersionEx(&ver))
590 {
591 switch(ver.dwPlatformId)
592 {
593 case VER_PLATFORM_WIN32_WINDOWS: // Windows 9x
594 LoadSubAgent("WIN9X.NSM");
595 break;
596 case VER_PLATFORM_WIN32_NT: // Windows NT or higher
597 LoadSubAgent("WINNT.NSM");
598 break;
599 default:
600 break;
601 }
602 }
603 else
604 {
605 nxlog_write(MSG_GETVERSION_FAILED, EVENTLOG_WARNING_TYPE, "e", GetLastError());
606 }
607}
608
609#else
610
203e9d8a 611void LoadPlatformSubagent()
5039dede
AK
612{
613#if defined(_NETWARE)
614 LoadSubAgent("NETWARE.NSM");
615#elif HAVE_SYS_UTSNAME_H && !defined(_STATIC_AGENT)
616 struct utsname un;
617 char szName[MAX_PATH];
618 int i;
619
620 if (uname(&un) != -1)
621 {
622 // Convert system name to lowercase
623 for(i = 0; un.sysname[i] != 0; i++)
624 un.sysname[i] = tolower(un.sysname[i]);
625 if (!strcmp(un.sysname, "hp-ux"))
626 strcpy(un.sysname, "hpux");
b0032c83 627 snprintf(szName, MAX_PATH, LIBDIR "/libnsm_%s" SHL_SUFFIX, un.sysname);
5039dede
AK
628 LoadSubAgent(szName);
629 }
630#endif
631}
632
633#endif
634
635
6173bea8
VK
636//
637// Send file to server (subagent API)
638//
639
640static BOOL SendFileToServer(void *session, DWORD requestId, const TCHAR *file, long offset)
641{
4685a2ad
VK
642 if (session == NULL)
643 return FALSE;
644
645 return ((CommSession *)session)->sendFile(requestId, file, offset);
6173bea8
VK
646}
647
648
b34606f7
VK
649//
650// Debug callback for DB library
651//
652
653static void DBLibraryDebugCallback(int level, const TCHAR *format, va_list args)
654{
15e11d1b 655 if (level <= (int)g_debugLevel)
b34606f7
VK
656 {
657 TCHAR buffer[4096];
658
659 _vsntprintf(buffer, 4096, format, args);
660 nxlog_write(MSG_DEBUG, EVENTLOG_DEBUG_TYPE, "s", buffer);
661 }
662}
663
664
5039dede
AK
665//
666// Initialization routine
667//
668
c6fbf758 669BOOL Initialize()
5039dede 670{
bf3b7f79
VK
671 TCHAR *pItem, *pEnd;
672 TCHAR regPath[MAX_PATH];
5039dede
AK
673#ifdef _NETWARE
674 char szLoadPath[1024], szSearchPath[1024];
675#endif
676
677 // Open log file
4addc3a3
VK
678 if (!(g_dwFlags & AF_USE_SYSLOG))
679 {
5945d50a 680 if (!nxlog_set_rotation_policy((int)m_dwLogRotationMode, (int)m_dwMaxLogSize, (int)m_dwLogHistorySize, m_szDailyLogFileSuffix))
4addc3a3 681 if (!(g_dwFlags & AF_DAEMON))
bf3b7f79 682 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
4addc3a3 683 }
9fcdfda7
VK
684 if (!nxlog_open((g_dwFlags & AF_USE_SYSLOG) ? NXAGENTD_SYSLOG_NAME : g_szLogFile,
685 ((g_dwFlags & AF_USE_SYSLOG) ? NXLOG_USE_SYSLOG : 0) |
686 ((g_dwFlags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
687 _T("NXAGENTD.EXE"),
5039dede 688#ifdef _WIN32
9fcdfda7 689 0, NULL))
5039dede 690#else
9fcdfda7 691 g_dwNumMessages, g_szMessages))
5039dede 692#endif
9fcdfda7 693 {
bf3b7f79 694 _ftprintf(stderr, _T("FATAL ERROR: Cannot open log file\n"));
9fcdfda7
VK
695 return FALSE;
696 }
203e9d8a
VK
697 nxlog_write(MSG_USE_CONFIG_D, NXLOG_INFO, "s", g_szConfigIncludeDir);
698 nxlog_write(MSG_DEBUG_LEVEL, NXLOG_INFO, "d", g_debugLevel);
699
0df58041
VK
700 if (_tcscmp(g_masterAgent, _T("not_set")))
701 {
702 g_dwFlags |= AF_SUBAGENT_LOADER;
703 DebugPrintf(INVALID_INDEX, 1, _T("Switched to external subagent loader mode, master agent address is %s"), g_masterAgent);
704 }
705
203e9d8a
VK
706 // Initialize persistent storage
707 s_registry = new Config;
708 s_registry->setTopLevelTag(_T("registry"));
709 nx_strncpy(regPath, g_szDataDirectory, MAX_PATH - _tcslen(REGISTRY_FILE_NAME) - 1);
710 if (regPath[_tcslen(regPath) - 1] != FS_PATH_SEPARATOR_CHAR)
711 _tcscat(regPath, FS_PATH_SEPARATOR);
712 _tcscat(regPath, REGISTRY_FILE_NAME);
713 if (!s_registry->loadXmlConfig(regPath, "registry"))
714 {
715 nxlog_write(MSG_REGISTRY_LOAD_FAILED, NXLOG_ERROR, "s", regPath);
716 SaveRegistry();
717 }
5039dede
AK
718
719#ifdef _WIN32
720 WSADATA wsaData;
1ddf3f0c
VK
721 int wrc = WSAStartup(MAKEWORD(2, 2), &wsaData);
722 if (wrc != 0)
5039dede 723 {
1ddf3f0c 724 nxlog_write(MSG_WSASTARTUP_FAILED, NXLOG_ERROR, "e", wrc);
5039dede
AK
725 return FALSE;
726 }
5039dede
AK
727#endif
728
729 // Add NLM load path to search list
730#ifdef _NETWARE
731 if (getnlmloadpath(szLoadPath) != NULL)
732 {
733 int i, nIsDOS;
734 BOOL bExist = FALSE;
735
736 for(i = 0; ; i++)
737 {
738 if (GetSearchPathElement(i, &nIsDOS, szSearchPath) != 0)
739 break;
740 if (strlen(szLoadPath) == szSearchPath[0])
741 if (!strncasecmp(&szSearchPath[1], szLoadPath, szSearchPath[0]))
742 {
743 bExist = TRUE;
744 break;
745 }
746 }
747 if (!bExist)
748 InsertSearchPath(getnetwarelogger(), 0, szLoadPath);
749 }
750#endif
751
752 // Initialize API for subagents
f480bdd4 753 InitSubAgentAPI(WriteSubAgentMsg, SendTrap, SendTrap, SendFileToServer, PushData);
bf3b7f79 754 DebugPrintf(INVALID_INDEX, 1, _T("Subagent API initialized"));
5039dede
AK
755
756 // Initialize cryptografy
757 if (!InitCryptoLib(m_dwEnabledCiphers))
758 {
759 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError());
760 return FALSE;
761 }
762
0df58041
VK
763 if (!(g_dwFlags & AF_SUBAGENT_LOADER))
764 {
765 InitSessionList();
766
767 // Initialize built-in parameters
768 if (!InitParameterList())
769 return FALSE;
5039dede
AK
770
771#ifdef _WIN32
0df58041
VK
772 // Dynamically import functions that may not be presented in all Windows versions
773 ImportSymbols();
5039dede
AK
774#endif
775
0df58041
VK
776 // Parse server list
777 if (m_pszServerList != NULL)
778 {
779 for(pItem = pEnd = m_pszServerList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
780 {
781 pEnd = strchr(pItem, ',');
782 if (pEnd != NULL)
783 *pEnd = 0;
784 StrStrip(pItem);
785 g_pServerList[g_dwServerCount].dwIpAddr = ResolveHostName(pItem);
786 if ((g_pServerList[g_dwServerCount].dwIpAddr == INADDR_NONE) ||
787 (g_pServerList[g_dwServerCount].dwIpAddr == INADDR_ANY))
788 {
789 if (!(g_dwFlags & AF_DAEMON))
790 printf("Invalid server address '%s'\n", pItem);
791 }
792 else
793 {
794 g_pServerList[g_dwServerCount].bMasterServer = FALSE;
795 g_pServerList[g_dwServerCount].bControlServer = FALSE;
796 g_dwServerCount++;
797 }
798 }
799 free(m_pszServerList);
800 }
5039dede 801
0df58041
VK
802 // Parse master server list
803 if (m_pszMasterServerList != NULL)
804 {
805 DWORD i, dwAddr;
5039dede 806
0df58041
VK
807 for(pItem = pEnd = m_pszMasterServerList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
808 {
809 pEnd = strchr(pItem, ',');
810 if (pEnd != NULL)
811 *pEnd = 0;
812 StrStrip(pItem);
813
814 dwAddr = ResolveHostName(pItem);
815 if ((dwAddr == INADDR_NONE) ||
816 (dwAddr == INADDR_ANY))
817 {
818 if (!(g_dwFlags & AF_DAEMON))
819 _tprintf(_T("Invalid server address '%s'\n"), pItem);
820 }
821 else
822 {
823 for(i = 0; i < g_dwServerCount; i++)
824 if (g_pServerList[i].dwIpAddr == dwAddr)
825 break;
826
827 if (i == g_dwServerCount)
828 {
829 g_pServerList[g_dwServerCount].dwIpAddr = dwAddr;
830 g_pServerList[g_dwServerCount].bMasterServer = TRUE;
831 g_pServerList[g_dwServerCount].bControlServer = TRUE;
832 g_dwServerCount++;
833 }
834 else
835 {
836 g_pServerList[i].bMasterServer = TRUE;
837 g_pServerList[i].bControlServer = TRUE;
838 }
839 }
840 }
841 free(m_pszMasterServerList);
842 }
5039dede 843
0df58041
VK
844 // Parse control server list
845 if (m_pszControlServerList != NULL)
846 {
847 DWORD i, dwAddr;
5039dede 848
0df58041
VK
849 for(pItem = pEnd = m_pszControlServerList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
850 {
851 pEnd = strchr(pItem, ',');
852 if (pEnd != NULL)
853 *pEnd = 0;
854 StrStrip(pItem);
855
856 dwAddr = ResolveHostName(pItem);
857 if ((dwAddr == INADDR_NONE) ||
858 (dwAddr == INADDR_ANY))
859 {
860 if (!(g_dwFlags & AF_DAEMON))
861 _tprintf(_T("Invalid server address '%s'\n"), pItem);
862 }
863 else
864 {
865 for(i = 0; i < g_dwServerCount; i++)
866 if (g_pServerList[i].dwIpAddr == dwAddr)
867 break;
868
869 if (i == g_dwServerCount)
870 {
871 g_pServerList[g_dwServerCount].dwIpAddr = dwAddr;
872 g_pServerList[g_dwServerCount].bMasterServer = FALSE;
873 g_pServerList[g_dwServerCount].bControlServer = TRUE;
874 g_dwServerCount++;
875 }
876 else
877 {
878 g_pServerList[i].bControlServer = TRUE;
879 }
880 }
881 }
882 free(m_pszControlServerList);
883 }
5039dede 884
0df58041
VK
885 // Add built-in actions
886 AddAction("Agent.Restart", AGENT_ACTION_SUBAGENT, NULL, H_RestartAgent, "CORE", "Restart agent");
5039dede 887
0df58041 888 // Load platform subagents
5039dede 889#if !defined(_WIN32) && !defined(_NETWARE)
0df58041 890 InitStaticSubagents();
5039dede 891#endif
0df58041
VK
892 if (g_dwFlags & AF_ENABLE_AUTOLOAD)
893 {
5039dede 894#ifdef _WIN32
0df58041 895 LoadWindowsSubagent();
5039dede 896#else
0df58041 897 LoadPlatformSubagent();
5039dede 898#endif
0df58041
VK
899 }
900 }
5039dede
AK
901
902 // Wait for external process if requested
903 if (m_szProcessToWait[0] != 0)
904 {
c303351c 905 DebugPrintf(INVALID_INDEX, 1, "Waiting for process %s", m_szProcessToWait);
5039dede
AK
906 if (!WaitForProcess(m_szProcessToWait))
907 nxlog_write(MSG_WAITFORPROCESS_FAILED, EVENTLOG_ERROR_TYPE, "s", m_szProcessToWait);
908 }
909
b34606f7
VK
910 DBSetDebugPrintCallback(DBLibraryDebugCallback);
911 DBInit(MSG_DB_LIBRARY, MSG_SQL_ERROR);
912
5039dede
AK
913 // Load other subagents
914 if (m_pszSubagentList != NULL)
915 {
e6c91aac 916 for(pItem = pEnd = m_pszSubagentList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
917 {
918 pEnd = strchr(pItem, '\n');
919 if (pEnd != NULL)
920 *pEnd = 0;
921 StrStrip(pItem);
922 LoadSubAgent(pItem);
923 }
924 free(m_pszSubagentList);
925 }
926
927 // Parse action list
928 if (m_pszActionList != NULL)
929 {
e6c91aac 930 for(pItem = pEnd = m_pszActionList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
931 {
932 pEnd = strchr(pItem, '\n');
933 if (pEnd != NULL)
934 *pEnd = 0;
935 StrStrip(pItem);
936 if (!AddActionFromConfig(pItem, FALSE))
937 nxlog_write(MSG_ADD_ACTION_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
938 }
939 free(m_pszActionList);
940 }
941 if (m_pszShellActionList != NULL)
942 {
e6c91aac 943 for(pItem = pEnd = m_pszShellActionList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede 944 {
bf3b7f79 945 pEnd = _tcschr(pItem, _T('\n'));
5039dede
AK
946
947 if (pEnd != NULL)
948 *pEnd = 0;
949 StrStrip(pItem);
950 if (!AddActionFromConfig(pItem, TRUE))
951 nxlog_write(MSG_ADD_ACTION_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
952 }
953 free(m_pszShellActionList);
954 }
955
956 // Parse external parameters list
957 if (m_pszExtParamList != NULL)
958 {
e6c91aac 959 for(pItem = pEnd = m_pszExtParamList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
960 {
961 pEnd = strchr(pItem, '\n');
962 if (pEnd != NULL)
963 *pEnd = 0;
964 StrStrip(pItem);
965 if (!AddExternalParameter(pItem, FALSE))
966 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
967 }
968 free(m_pszExtParamList);
969 }
970 if (m_pszShExtParamList != NULL)
971 {
e6c91aac 972 for(pItem = pEnd = m_pszShExtParamList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
5039dede
AK
973 {
974 pEnd = strchr(pItem, '\n');
975 if (pEnd != NULL)
976 *pEnd = 0;
977 StrStrip(pItem);
978 if (!AddExternalParameter(pItem, TRUE))
979 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
980 }
981 free(m_pszShExtParamList);
982 }
983
9795113c
VK
984 // Parse external parameters providers list
985 if (m_pszParamProviderList != NULL)
986 {
987 for(pItem = pEnd = m_pszParamProviderList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
988 {
989 pEnd = strchr(pItem, '\n');
990 if (pEnd != NULL)
991 *pEnd = 0;
992 StrStrip(pItem);
993 if (!AddParametersProvider(pItem))
994 nxlog_write(MSG_ADD_PARAM_PROVIDER_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
995 }
996 free(m_pszParamProviderList);
997 }
998
204ace22 999 // Parse external subagents list
0df58041 1000 if (!(g_dwFlags & AF_SUBAGENT_LOADER) && (m_pszExtSubagentList != NULL))
204ace22
VK
1001 {
1002 for(pItem = pEnd = m_pszExtSubagentList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
1003 {
1004 pEnd = strchr(pItem, '\n');
1005 if (pEnd != NULL)
1006 *pEnd = 0;
1007 StrStrip(pItem);
1008 if (!AddExternalSubagent(pItem))
1009 nxlog_write(MSG_ADD_EXTERNAL_SUBAGENT_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
1010 }
1011 free(m_pszExtSubagentList);
1012 }
1013
5039dede
AK
1014 ThreadSleep(1);
1015
1016 // If StartupDelay is greater than zero, then wait
1017 if (g_dwStartupDelay > 0)
1018 {
1019 if (g_dwFlags & AF_DAEMON)
1020 {
1021 ThreadSleep(g_dwStartupDelay);
1022 }
1023 else
1024 {
1025 DWORD i;
1026
1027 printf("XXXXXX%*s]\rWAIT [", g_dwStartupDelay, " ");
1028 fflush(stdout);
1029 for(i = 0; i < g_dwStartupDelay; i++)
1030 {
1031 ThreadSleep(1);
1032 putc('.', stdout);
1033 fflush(stdout);
1034 }
1035 printf("\n");
1036 }
1037 }
1038
9795113c
VK
1039 StartParamProvidersPoller();
1040
5039dede
AK
1041 // Agent start time
1042 g_tmAgentStartTime = time(NULL);
1043
0df58041
VK
1044 if (g_dwFlags & AF_SUBAGENT_LOADER)
1045 {
1046 m_thMasterAgentListener = ThreadCreateEx(MasterAgentListener, 0, NULL);
1047 }
1048 else
1049 {
1050 // Start network listener and session watchdog
1051 m_thListener = ThreadCreateEx(ListenerThread, 0, NULL);
1052 m_thSessionWatchdog = ThreadCreateEx(SessionWatchdog, 0, NULL);
1053 m_thTrapSender = ThreadCreateEx(TrapSender, 0, NULL);
0bd64860 1054 StartPushConnector();
0df58041 1055 }
5039dede
AK
1056
1057#if defined(_WIN32) || defined(_NETWARE)
1058 m_hCondShutdown = ConditionCreate(TRUE);
1059#endif
1060 ThreadSleep(1);
1061
9fcdfda7 1062 // Start watchdog process
0df58041
VK
1063 if (!(g_dwFlags & AF_SUBAGENT_LOADER))
1064 {
1065 if (g_dwFlags & AF_ENABLE_WATCHDOG)
1066 StartWatchdog();
1067 }
9fcdfda7 1068
c6fbf758
VK
1069 delete g_config;
1070
5039dede
AK
1071 return TRUE;
1072}
1073
1074
1075//
1076// Shutdown routine
1077//
1078
0df58041 1079void Shutdown()
5039dede 1080{
8e954797 1081 DebugPrintf(INVALID_INDEX, 2, _T("Shutdown() called"));
9fcdfda7
VK
1082 if (g_dwFlags & AF_ENABLE_WATCHDOG)
1083 StopWatchdog();
1084
5039dede 1085 g_dwFlags |= AF_SHUTDOWN;
0df58041
VK
1086
1087 if (g_dwFlags & AF_SUBAGENT_LOADER)
1088 {
639088d4
VK
1089 // TODO: shall we inform master agent listener about shutdown?
1090 //ThreadJoin(m_thMasterAgentListener);
0df58041
VK
1091 }
1092 else
1093 {
1094 ShutdownTrapSender();
1095 ThreadJoin(m_thSessionWatchdog);
1096 ThreadJoin(m_thListener);
1097 ThreadJoin(m_thTrapSender);
1098 }
5039dede
AK
1099
1100 UnloadAllSubAgents();
1101 nxlog_write(MSG_AGENT_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
1102 nxlog_close();
1103
1104 // Notify main thread about shutdown
1105#ifdef _WIN32
1106 ConditionSet(m_hCondShutdown);
1107#endif
1108
1109 // Remove PID file
1110#if !defined(_WIN32) && !defined(_NETWARE)
1111 remove(g_szPidFile);
1112#endif
1113}
1114
1115
1116//
1117// Common Main()
1118//
1119
8ec102ac 1120void Main()
5039dede 1121{
8ec102ac 1122 nxlog_write(MSG_AGENT_STARTED, NXLOG_INFO, NULL);
5039dede
AK
1123
1124 if (g_dwFlags & AF_DAEMON)
1125 {
1126#if defined(_WIN32) || defined(_NETWARE)
1127 ConditionWait(m_hCondShutdown, INFINITE);
1128#else
1129 StartMainLoop(SignalHandler, NULL);
1130#endif
1131 }
1132 else
1133 {
1134#if defined(_WIN32)
1135 if (g_dwFlags & AF_HIDE_WINDOW)
1136 {
1137 HWND hWnd;
1138
1139 hWnd = GetConsoleHWND();
1140 if (hWnd != NULL)
1141 ShowWindow(hWnd, SW_HIDE);
1142 ConditionWait(m_hCondShutdown, INFINITE);
1143 ThreadSleep(1);
1144 }
1145 else
1146 {
1147 printf("Agent running. Press ESC to shutdown.\n");
1148 while(1)
1149 {
3973f74b 1150 if (_getch() == 27)
5039dede
AK
1151 break;
1152 }
1153 printf("Agent shutting down...\n");
1154 Shutdown();
1155 }
1156#elif defined(_NETWARE)
1157 printf("Agent running. Type UNLOAD NXAGENTD on the system console for shutdown.\n");
1158 ConditionWait(m_hCondShutdown, INFINITE);
1159#else
1160 printf("Agent running. Press Ctrl+C to shutdown.\n");
1161 StartMainLoop(SignalHandler, NULL);
1162 printf("\nStopping agent...\n");
1163#endif
1164 }
1165}
1166
1167
1168//
1169// Do necessary actions on agent restart
1170//
1171
1172static void DoRestartActions(DWORD dwOldPID)
1173{
1174#if defined(_WIN32)
1175 if (dwOldPID == 0)
1176 {
1177 // Service
1178 StopAgentService();
1179 WaitForService(SERVICE_STOPPED);
1180 StartAgentService();
1181 ExitProcess(0);
1182 }
1183 else
1184 {
1185 HANDLE hProcess;
1186
1187 hProcess = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, dwOldPID);
1188 if (hProcess != NULL)
1189 {
1190 if (WaitForSingleObject(hProcess, 60000) == WAIT_TIMEOUT)
1191 {
1192 TerminateProcess(hProcess, 0);
1193 }
1194 CloseHandle(hProcess);
1195 }
1196 }
1197#elif defined(_NETWARE)
1198 /* TODO: implement restart for NetWare */
1199#else
1200 int i;
1201
1202 kill(dwOldPID, SIGTERM);
1203 for(i = 0; i < 30; i++)
1204 {
1205 sleep(2);
1206 if (kill(dwOldPID, SIGCONT) == -1)
1207 break;
1208 }
1209
1210 // Kill previous instance of agent if it's still running
1211 if (i == 30)
1212 kill(dwOldPID, SIGKILL);
1213#endif
1214}
1215
1216
1217//
1218// NetWare exit handler
1219//
1220
1221#ifdef _NETWARE
1222
1223static void ExitHandler(int nSig)
1224{
1225 printf("\n*** Unloading NetXMS agent ***\n");
1226 ConditionSet(m_hCondShutdown);
1227 while(g_nThreadCount > 0)
1228 pthread_yield();
1229}
1230
1231#endif
1232
1233
1234//
1235// Create configuration file
1236//
1237
48dd3c80
VK
1238static int CreateConfig(const TCHAR *pszServer, const TCHAR *pszLogFile, const TCHAR *pszFileStore,
1239 const TCHAR *configIncludeDir, int iNumSubAgents, TCHAR **ppszSubAgentList)
5039dede
AK
1240{
1241 FILE *fp;
1242 time_t currTime;
1243 int i;
1244
1245 if (_taccess(g_szConfigFile, 0) == 0)
1246 return 0; // File already exist, we shouldn't overwrite it
1247
1248 fp = _tfopen(g_szConfigFile, _T("w"));
1249 if (fp != NULL)
1250 {
1251 currTime = time(NULL);
1252 _ftprintf(fp, _T("#\n# NetXMS agent configuration file\n# Created by agent installer at %s#\n\n"),
1253 _tctime(&currTime));
48dd3c80
VK
1254 _ftprintf(fp, _T("MasterServers = %s\nConfigIncludeDir = %s\nLogFile = %s\nFileStore = %s\n"),
1255 pszServer, configIncludeDir, pszLogFile, pszFileStore);
5039dede
AK
1256 for(i = 0; i < iNumSubAgents; i++)
1257 _ftprintf(fp, _T("SubAgent = %s\n"), ppszSubAgentList[i]);
1258 fclose(fp);
1259 }
1260 return (fp != NULL) ? 0 : 2;
1261}
1262
1263
e6c91aac
VK
1264//
1265// Init config
1266//
1267
1268static void InitConfig()
1269{
1270 g_config = new Config();
8a0dffac 1271 g_config->setTopLevelTag(_T("config"));
e6c91aac
VK
1272}
1273
1274
5039dede
AK
1275//
1276// Startup
1277//
1278
1279int main(int argc, char *argv[])
1280{
1281 int ch, iExitCode = 0, iAction = ACTION_RUN_AGENT;
1282 BOOL bRestart = FALSE;
9fcdfda7 1283 DWORD dwOldPID, dwMainPID;
bf3b7f79 1284 TCHAR *eptr;
5039dede 1285#ifdef _WIN32
bf3b7f79 1286 TCHAR szModuleName[MAX_PATH];
1621a079
VK
1287 HKEY hKey;
1288 DWORD dwSize;
1289#else
1290 char *pszEnv;
5039dede
AK
1291#endif
1292
1293 InitThreadLibrary();
9fcdfda7
VK
1294
1295#ifdef NETXMS_MEMORY_DEBUG
1296 InitMemoryDebugger();
1297#endif
5039dede
AK
1298
1299#ifdef _NETWARE
1300 g_nThreadCount++;
1301 setscreenmode(SCR_AUTOCLOSE_ON_EXIT | SCR_COLOR_ATTRS);
1302#endif
1303
1304 // Set locale to C. It shouldn't be needed, according to
1305 // documentation, but I've seen the cases when agent formats
1306 // floating point numbers by sprintf inserting comma in place
1307 // of a dot, as set by system's regional settings.
1308#ifdef _WIN32
1309 setlocale(LC_ALL, "C");
1310#endif
1311
1621a079
VK
1312 // Check for alternate config file location
1313#ifdef _WIN32
1314 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Agent"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
1315 {
1316 dwSize = MAX_PATH * sizeof(TCHAR);
1317 RegQueryValueEx(hKey, _T("ConfigFile"), NULL, NULL, (BYTE *)g_szConfigFile, &dwSize);
42acd918 1318 dwSize = MAX_PATH * sizeof(TCHAR);
1621a079
VK
1319 RegQueryValueEx(hKey, _T("ConfigIncludeDir"), NULL, NULL, (BYTE *)g_szConfigIncludeDir, &dwSize);
1320 RegCloseKey(hKey);
1321 }
1322#else
1323 pszEnv = _tgetenv(_T("NXAGENTD_CONFIG"));
1324 if (pszEnv != NULL)
1325 nx_strncpy(g_szConfigFile, pszEnv, MAX_PATH);
1326
1327 pszEnv = _tgetenv(_T("NXAGENTD_CONFIG_D"));
1328 if (pszEnv != NULL)
1329 nx_strncpy(g_szConfigIncludeDir, pszEnv, MAX_PATH);
1330#endif
1331
5039dede
AK
1332 // Parse command line
1333 if (argc == 1)
1334 iAction = ACTION_HELP;
1335 opterr = 1;
1336 while((ch = getopt(argc, argv, VALID_OPTIONS)) != -1)
1337 {
1338 switch(ch)
1339 {
1340 case 'h': // Display help and exit
1341 iAction = ACTION_HELP;
1342 break;
1343 case 'd': // Run as daemon
1344 g_dwFlags |= AF_DAEMON;
1345 break;
1346 case 'f': // Run in foreground
1347 g_dwFlags &= ~AF_DAEMON;
1348 break;
1349 case 'D': // Turn on debug output
53c96e2d
VK
1350 g_debugLevel = strtoul(optarg, &eptr, 0);
1351 if ((*eptr != 0) || (g_debugLevel > 9))
c303351c
VK
1352 {
1353 fprintf(stderr, "Invalid debug level: %s\n", optarg);
1354 iAction = -1;
1355 iExitCode = 1;
1356 }
5039dede
AK
1357 break;
1358 case 'c': // Configuration file
1359 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
1360 break;
1361#if !defined(_WIN32) && !defined(_NETWARE)
1362 case 'p': // PID file
1363 nx_strncpy(g_szPidFile, optarg, MAX_PATH);
1364 break;
1365#endif
1366 case 'C': // Configuration check only
1367 iAction = ACTION_CHECK_CONFIG;
1368 break;
1369 case 'v': // Print version and exit
1370 printf("NetXMS Core Agent Version " AGENT_VERSION_STRING "\n");
1371 iAction = ACTION_NONE;
1372 break;
1373 case 'M':
1374 g_dwFlags |= AF_CENTRAL_CONFIG;
1375 nx_strncpy(g_szConfigServer, optarg, MAX_DB_STRING);
1376 break;
1377 case 'r':
1378 g_dwFlags |= AF_REGISTER;
1379 nx_strncpy(g_szRegistrar, optarg, MAX_DB_STRING);
1380 break;
1381 case 'P': // Platform suffix
1382 nx_strncpy(g_szPlatformSuffix, optarg, MAX_PSUFFIX_LENGTH);
1383 break;
1384 case 'X': // Agent is being restarted
1385 bRestart = TRUE;
1386 dwOldPID = strtoul(optarg, NULL, 10);
1387 break;
9fcdfda7
VK
1388 case 'W': // Watchdog process
1389 iAction = ACTION_RUN_WATCHDOG;
1390 dwMainPID = strtoul(optarg, NULL, 10);
1391 break;
5039dede
AK
1392 case 'Z': // Create configuration file
1393 iAction = ACTION_CREATE_CONFIG;
1394 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
1395 break;
1396#ifdef _WIN32
1397 case 'H': // Hide window
1398 g_dwFlags |= AF_HIDE_WINDOW;
1399 break;
175bd003
VK
1400 case 'i':
1401 g_dwFlags |= AF_INTERACTIVE_SERVICE;
1402 break;
5039dede
AK
1403 case 'I': // Install Windows service
1404 iAction = ACTION_INSTALL_SERVICE;
1405 break;
1406 case 'R': // Remove Windows service
1407 iAction = ACTION_REMOVE_SERVICE;
1408 break;
1409 case 's': // Start Windows service
1410 iAction = ACTION_START_SERVICE;
1411 break;
1412 case 'S': // Stop Windows service
1413 iAction = ACTION_STOP_SERVICE;
1414 break;
1415 case 'E': // Install Windows event source
1416 iAction = ACTION_INSTALL_EVENT_SOURCE;
1417 break;
1418 case 'U': // Remove Windows event source
1419 iAction = ACTION_REMOVE_EVENT_SOURCE;
1420 break;
9f96fc88
VK
1421 case 'e': // Event source name
1422 nx_strncpy(g_windowsEventSourceName, optarg, MAX_PATH);
1423 break;
1424 case 'n': // Service name
1425 nx_strncpy(g_windowsServiceName, optarg, MAX_PATH);
1426 break;
1427 case 'N': // Service display name
1428 nx_strncpy(g_windowsServiceDisplayName, optarg, MAX_PATH);
1429 break;
5039dede
AK
1430#endif
1431 case '?':
1432 iAction = ACTION_HELP;
1433 iExitCode = 1;
1434 break;
1435 default:
1436 break;
1437 }
1438 }
1439
1440#if !defined(_WIN32) && !defined(_NETWARE)
1441 if (!_tcscmp(g_szConfigFile, _T("{search}")))
1442 {
1443 if (access(PREFIX "/etc/nxagentd.conf", 4) == 0)
1444 {
1445 _tcscpy(g_szConfigFile, PREFIX "/etc/nxagentd.conf");
1446 }
1447 else if (access("/usr/etc/nxagentd.conf", 4) == 0)
1448 {
1449 _tcscpy(g_szConfigFile, "/usr/etc/nxagentd.conf");
1450 }
1451 else
1452 {
1453 _tcscpy(g_szConfigFile, "/etc/nxagentd.conf");
1454 }
1455 }
80ce37ac 1456 if (!_tcscmp(g_szConfigIncludeDir, _T("{search}")))
abf35d58
VK
1457 {
1458 if (access(PREFIX "/etc/nxagentd.conf.d", 4) == 0)
1459 {
80ce37ac 1460 _tcscpy(g_szConfigIncludeDir, PREFIX "/etc/nxagentd.conf.d");
abf35d58
VK
1461 }
1462 else if (access("/usr/etc/nxagentd.conf.d", 4) == 0)
1463 {
80ce37ac 1464 _tcscpy(g_szConfigIncludeDir, "/usr/etc/nxagentd.conf.d");
abf35d58
VK
1465 }
1466 else
1467 {
80ce37ac 1468 _tcscpy(g_szConfigIncludeDir, "/etc/nxagentd.conf.d");
abf35d58
VK
1469 }
1470 }
5039dede
AK
1471#endif
1472
1473 if (bRestart)
1474 DoRestartActions(dwOldPID);
1475
e6c91aac
VK
1476 InitConfig();
1477
5039dede
AK
1478 // Do requested action
1479 switch(iAction)
1480 {
1481 case ACTION_RUN_AGENT:
1482 // Set default value for session idle timeout based on
1483 // connect() timeout, if possible
1484#if HAVE_SYSCTLBYNAME && !defined(_IPSO)
1485 {
1486 LONG nVal;
1487 size_t nSize;
1488
1489 nSize = sizeof(nVal);
1490 if (sysctlbyname("net.inet.tcp.keepinit", &nVal, &nSize, NULL, 0) == 0)
1491 {
1492 g_dwIdleTimeout = nVal / 1000 + 15;
1493 }
1494 }
1495#endif
1496
1497 if (g_dwFlags & AF_CENTRAL_CONFIG)
1498 {
c303351c 1499 if (g_debugLevel > 0)
5039dede
AK
1500 printf("Downloading configuration from %s...\n", g_szConfigServer);
1501 if (DownloadConfig(g_szConfigServer))
1502 {
c303351c 1503 if (g_debugLevel > 0)
5039dede
AK
1504 printf("Configuration downloaded successfully\n");
1505 }
1506 else
1507 {
c303351c 1508 if (g_debugLevel > 0)
5039dede
AK
1509 printf("Configuration download failed\n");
1510 }
1511 }
1512
abf35d58 1513 if (g_config->loadConfig(g_szConfigFile, _T("agent")))
e6c91aac 1514 {
357a2954
AK
1515 const TCHAR *dir = g_config->getValue(_T("/agent/ConfigIncludeDir"));
1516 if (dir != NULL)
6ca3b41c
VK
1517 nx_strncpy(g_szConfigIncludeDir, dir, MAX_PATH);
1518 g_config->loadConfigDirectory(g_szConfigIncludeDir, _T("agent"));
abf35d58
VK
1519 if (g_config->parseTemplate(_T("agent"), m_cfgTemplate))
1520 {
0bbab9d3 1521 // Set exception handler
9fcdfda7 1522#ifdef _WIN32
abf35d58
VK
1523 if (g_dwFlags & AF_CATCH_EXCEPTIONS)
1524 SetExceptionHandler(SEHServiceExceptionHandler, SEHServiceExceptionDataWriter, m_szDumpDir,
bf3b7f79 1525 _T("nxagentd"), MSG_EXCEPTION, g_dwFlags & AF_WRITE_FULL_DUMP, !(g_dwFlags & AF_DAEMON));
abf35d58 1526 __try {
9fcdfda7 1527#endif
bf3b7f79
VK
1528 if ((!_tcsicmp(g_szLogFile, _T("{syslog}"))) ||
1529 (!_tcsicmp(g_szLogFile, _T("{eventlog}"))))
abf35d58 1530 g_dwFlags |= AF_USE_SYSLOG;
5039dede
AK
1531
1532#ifdef _WIN32
abf35d58
VK
1533 if (g_dwFlags & AF_DAEMON)
1534 {
1535 InitService();
1536 }
1537 else
1538 {
1539 if (Initialize())
1540 {
1541 Main();
1542 }
1543 else
1544 {
bf3b7f79 1545 ConsolePrintf(_T("Agent initialization failed\n"));
abf35d58
VK
1546 nxlog_close();
1547 iExitCode = 3;
1548 }
1549 }
5039dede
AK
1550#else /* _WIN32 */
1551#ifndef _NETWARE
abf35d58
VK
1552 if (g_dwFlags & AF_DAEMON)
1553 if (daemon(0, 0) == -1)
1554 {
1555 perror("Unable to setup itself as a daemon");
1556 iExitCode = 4;
1557 }
5039dede 1558#endif
abf35d58 1559 if (iExitCode == 0)
5039dede
AK
1560 {
1561#ifndef _NETWARE
abf35d58 1562 m_pid = getpid();
5039dede 1563#endif
abf35d58
VK
1564 if (Initialize())
1565 {
5039dede 1566#ifdef _NETWARE
abf35d58 1567 signal(SIGTERM, ExitHandler);
5039dede 1568#else
abf35d58
VK
1569 FILE *fp;
1570
1571 // Write PID file
1572 fp = fopen(g_szPidFile, "w");
1573 if (fp != NULL)
1574 {
1575 fprintf(fp, "%d", m_pid);
1576 fclose(fp);
1577 }
5039dede 1578#endif
abf35d58
VK
1579 Main();
1580 Shutdown();
1581 }
1582 else
1583 {
bf3b7f79 1584 ConsolePrintf(_T("Agent initialization failed\n"));
abf35d58
VK
1585 nxlog_close();
1586 iExitCode = 3;
1587 }
1588 }
5039dede
AK
1589#endif /* _WIN32 */
1590
1591#if defined(_WIN32) || defined(_NETWARE)
abf35d58
VK
1592 if (m_hCondShutdown != INVALID_CONDITION_HANDLE)
1593 ConditionDestroy(m_hCondShutdown);
9fcdfda7
VK
1594#endif
1595#ifdef _WIN32
abf35d58 1596 LIBNETXMS_EXCEPTION_HANDLER
5039dede 1597#endif
abf35d58
VK
1598 }
1599 else
1600 {
bf3b7f79 1601 ConsolePrintf(_T("Error parsing configuration file\n"));
abf35d58
VK
1602 iExitCode = 2;
1603 }
5039dede
AK
1604 }
1605 else
1606 {
bf3b7f79 1607 ConsolePrintf(_T("Error loading configuration file\n"));
5039dede
AK
1608 iExitCode = 2;
1609 }
1610 break;
1611 case ACTION_CHECK_CONFIG:
97a92859 1612 if (!g_config->loadIniConfig(g_szConfigFile, _T("agent")) || !g_config->parseTemplate(_T("agent"), m_cfgTemplate))
5039dede 1613 {
bf3b7f79 1614 ConsolePrintf(_T("Configuration file check failed\n"));
5039dede
AK
1615 iExitCode = 2;
1616 }
1617 break;
9fcdfda7
VK
1618 case ACTION_RUN_WATCHDOG:
1619 iExitCode = WatchdogMain(dwMainPID);
1620 break;
5039dede
AK
1621 case ACTION_CREATE_CONFIG:
1622 iExitCode = CreateConfig(CHECK_NULL(argv[optind]), CHECK_NULL(argv[optind + 1]),
48dd3c80
VK
1623 CHECK_NULL(argv[optind + 2]), CHECK_NULL(argv[optind + 3]),
1624 argc - optind - 4, &argv[optind + 4]);
5039dede
AK
1625 break;
1626#ifdef _WIN32
1627 case ACTION_INSTALL_SERVICE:
1628 GetModuleFileName(GetModuleHandle(NULL), szModuleName, MAX_PATH);
1629 InstallService(szModuleName, g_szConfigFile);
1630 break;
1631 case ACTION_REMOVE_SERVICE:
1632 RemoveService();
1633 break;
1634 case ACTION_INSTALL_EVENT_SOURCE:
1635 GetModuleFileName(GetModuleHandle(NULL), szModuleName, MAX_PATH);
1636 InstallEventSource(szModuleName);
1637 break;
1638 case ACTION_REMOVE_EVENT_SOURCE:
1639 RemoveEventSource();
1640 break;
1641 case ACTION_START_SERVICE:
1642 StartAgentService();
1643 break;
1644 case ACTION_STOP_SERVICE:
1645 StopAgentService();
1646 break;
1647#endif
1648 case ACTION_HELP:
9fcdfda7 1649 fputs(m_szHelpText, stdout);
5039dede
AK
1650 break;
1651 default:
1652 break;
1653 }
1654
1655#ifdef _NETWARE
1656 if ((iExitCode != 0) || (iAction == ACTION_NONE) ||
1657 (iAction == ACTION_CHECK_CONFIG))
1658 setscreenmode(SCR_NO_MODE);
1659 g_nThreadCount--;
1660#endif
1661
1662 return iExitCode;
1663}