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