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