2 ** NetXMS multiplatform core agent
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
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.
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
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.
37 #if HAVE_SYS_UTSNAME_H
38 #include <sys/utsname.h>
42 #include <sys/sysctl.h>
45 #ifdef _WITH_ENCRYPTION
46 #include <openssl/ssl.h>
60 THREAD_RESULT THREAD_CALL
ListenerThread(void *);
61 THREAD_RESULT THREAD_CALL
SessionWatchdog(void *);
62 THREAD_RESULT THREAD_CALL
TrapSender(void *);
63 THREAD_RESULT THREAD_CALL
MasterAgentListener(void *arg
);
64 THREAD_RESULT THREAD_CALL
SNMPTrapReceiver(void *);
65 THREAD_RESULT THREAD_CALL
SNMPTrapSender(void *);
67 void ShutdownTrapSender();
68 void ShutdownSNMPTrapSender();
70 void StartLocalDataCollector();
71 void ShutdownLocalDataCollector();
75 int WatchdogMain(DWORD pid
);
77 void InitSessionList();
78 void DestroySessionList();
80 BOOL
RegisterOnServer(const TCHAR
*pszServer
);
82 void UpdatePolicyInventory();
85 void InitStaticSubagents();
89 extern TCHAR g_windowsServiceName
[];
90 extern TCHAR g_windowsServiceDisplayName
[];
93 void LIBNXAGENT_EXPORTABLE
InitSubAgentAPI(void (* writeLog
)(int, int, const TCHAR
*),
94 void (* sendTrap1
)(UINT32
, const TCHAR
*, const char *, va_list),
95 void (* sendTrap2
)(UINT32
, const TCHAR
*, int, TCHAR
**),
96 bool (* enumerateSessions
)(EnumerationCallbackResult (*)(AbstractCommSession
*, void *), void*),
97 AbstractCommSession
*(* findServerSession
)(UINT64
),
98 bool (* sendFile
)(void *, UINT32
, const TCHAR
*, long),
99 bool (* pushData
)(const TCHAR
*, const TCHAR
*, UINT32
, time_t),
100 DB_HANDLE (* getLocalDatabaseHandle
)(),
101 CONDITION shutdownCondition
, const TCHAR
*dataDirectory
);
104 * Messages generated by mc.pl (for UNIX version only)
107 extern unsigned int g_dwNumMessages
;
108 extern const TCHAR
*g_szMessages
[];
112 * Valid options for getopt()
115 #define VALID_OPTIONS "c:CdD:e:EfhHiIKM:n:N:P:r:RsSUvX:W:Z:"
117 #define VALID_OPTIONS "c:CdD:fg:hKM:p:P:r:u:vX:W:Z:"
123 #define ACTION_NONE 0
124 #define ACTION_RUN_AGENT 1
125 #define ACTION_INSTALL_SERVICE 2
126 #define ACTION_REMOVE_SERVICE 3
127 #define ACTION_START_SERVICE 4
128 #define ACTION_STOP_SERVICE 5
129 #define ACTION_CHECK_CONFIG 6
130 #define ACTION_INSTALL_EVENT_SOURCE 7
131 #define ACTION_REMOVE_EVENT_SOURCE 8
132 #define ACTION_CREATE_CONFIG 9
133 #define ACTION_HELP 10
134 #define ACTION_RUN_WATCHDOG 11
135 #define ACTION_SHUTDOWN_EXT_AGENTS 12
140 UINT32 g_dwFlags
= AF_ENABLE_ACTIONS
| AF_ENABLE_AUTOLOAD
;
141 UINT32 g_failFlags
= 0;
142 TCHAR g_szLogFile
[MAX_PATH
] = AGENT_DEFAULT_LOG
;
143 TCHAR g_szSharedSecret
[MAX_SECRET_LENGTH
] = _T("admin");
144 TCHAR g_szConfigFile
[MAX_PATH
] = AGENT_DEFAULT_CONFIG
;
145 TCHAR g_szFileStore
[MAX_PATH
] = AGENT_DEFAULT_FILE_STORE
;
146 TCHAR g_szDataDirectory
[MAX_PATH
] = AGENT_DEFAULT_DATA_DIR
;
147 TCHAR g_szPlatformSuffix
[MAX_PSUFFIX_LENGTH
] = _T("");
148 TCHAR g_szConfigServer
[MAX_DB_STRING
] = _T("not_set");
149 TCHAR g_szRegistrar
[MAX_DB_STRING
] = _T("not_set");
150 TCHAR g_szListenAddress
[MAX_PATH
] = _T("*");
151 TCHAR g_szConfigIncludeDir
[MAX_PATH
] = AGENT_DEFAULT_CONFIG_D
;
152 TCHAR g_szConfigPolicyDir
[MAX_PATH
] = AGENT_DEFAULT_CONFIG_D
;
153 TCHAR g_szLogParserDirectory
[MAX_PATH
] = _T("");
154 TCHAR g_masterAgent
[MAX_PATH
] = _T("not_set");
155 TCHAR g_szSNMPTrapListenAddress
[MAX_PATH
] = _T("*");
156 UINT16 g_wListenPort
= AGENT_LISTEN_PORT
;
157 ObjectArray
<ServerInfo
> g_serverList(8, 8, true);
158 UINT32 g_dwServerCount
= 0;
159 UINT32 g_dwExecTimeout
= 2000; // External process execution timeout in milliseconds
160 UINT32 g_dwSNMPTimeout
= 1500;
161 time_t g_tmAgentStartTime
;
162 UINT32 g_dwStartupDelay
= 0;
163 UINT32 g_dwMaxSessions
= 32;
164 UINT32 g_dwSNMPTrapPort
= 162;
165 UINT32 g_longRunningQueryThreshold
= 250;
166 UINT32 g_dcReconciliationBlockSize
= 1024;
167 UINT32 g_dcReconciliationTimeout
= 15000;
168 UINT32 g_dcMaxCollectorPoolSize
= 64;
171 UINT16 g_sessionAgentPort
= 28180;
173 UINT16 g_sessionAgentPort
= 0;
175 Config
*g_config
= NULL
;
177 UINT32 g_dwIdleTimeout
= 60; // Session idle timeout
179 UINT32 g_dwIdleTimeout
= 120; // Session idle timeout
183 TCHAR g_szPidFile
[MAX_PATH
] = _T("/var/run/nxagentd.pid");
189 static TCHAR
*m_pszActionList
= NULL
;
190 static TCHAR
*m_pszShellActionList
= NULL
;
191 static TCHAR
*m_pszServerList
= NULL
;
192 static TCHAR
*m_pszControlServerList
= NULL
;
193 static TCHAR
*m_pszMasterServerList
= NULL
;
194 static TCHAR
*m_pszSubagentList
= NULL
;
195 static TCHAR
*m_pszExtParamList
= NULL
;
196 static TCHAR
*m_pszExtListsList
= NULL
;
197 static TCHAR
*m_pszShExtParamList
= NULL
;
198 static TCHAR
*m_pszParamProviderList
= NULL
;
199 static TCHAR
*m_pszExtSubagentList
= NULL
;
200 static TCHAR
*m_pszAppAgentList
= NULL
;
201 static UINT32 s_enabledCiphers
= 0xFFFF;
202 static THREAD s_sessionWatchdogThread
= INVALID_THREAD_HANDLE
;
203 static THREAD s_listenerThread
= INVALID_THREAD_HANDLE
;
204 static THREAD s_eventSenderThread
= INVALID_THREAD_HANDLE
;
205 static THREAD s_snmpTrapReceiverThread
= INVALID_THREAD_HANDLE
;
206 static THREAD s_snmpTrapSenderThread
= INVALID_THREAD_HANDLE
;
207 static THREAD s_masterAgentListenerThread
= INVALID_THREAD_HANDLE
;
208 static TCHAR s_processToWaitFor
[MAX_PATH
] = _T("");
209 static TCHAR s_dumpDir
[MAX_PATH
] = _T("C:\\");
210 static UINT64 s_maxLogSize
= 16384 * 1024;
211 static UINT32 s_logHistorySize
= 4;
212 static UINT32 s_logRotationMode
= NXLOG_ROTATION_BY_SIZE
;
213 static TCHAR s_dailyLogFileSuffix
[64] = _T("");
214 static TCHAR s_executableName
[MAX_PATH
];
215 static UINT32 s_debugLevel
= (UINT32
)NXCONFIG_UNINITIALIZED_VALUE
;
217 static CONDITION s_subAgentsStopCondition
= INVALID_CONDITION_HANDLE
;
219 static CONDITION s_shutdownCondition
= INVALID_CONDITION_HANDLE
;
227 * Configuration file template
229 static NX_CFG_TEMPLATE m_cfgTemplate
[] =
231 { _T("Action"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszActionList
, NULL
},
232 { _T("ActionShellExec"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszShellActionList
, NULL
},
233 { _T("AppAgent"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszAppAgentList
, NULL
},
234 { _T("BackgroundLogWriter"), CT_BOOLEAN
, 0, 0, AF_BACKGROUND_LOG_WRITER
, 0, &g_dwFlags
, NULL
},
235 { _T("ControlServers"), CT_STRING_LIST
, ',', 0, 0, 0, &m_pszControlServerList
, NULL
},
236 { _T("CreateCrashDumps"), CT_BOOLEAN
, 0, 0, AF_CATCH_EXCEPTIONS
, 0, &g_dwFlags
, NULL
},
237 { _T("DataCollectionThreadPoolSize"), CT_LONG
, 0, 0, 0, 0, &g_dcMaxCollectorPoolSize
, NULL
},
238 { _T("DataDirectory"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szDataDirectory
, NULL
},
239 { _T("DataReconciliationBlockSize"), CT_LONG
, 0, 0, 0, 0, &g_dcReconciliationBlockSize
, NULL
},
240 { _T("DataReconciliationTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dcReconciliationTimeout
, NULL
},
241 { _T("DailyLogFileSuffix"), CT_STRING
, 0, 0, 64, 0, s_dailyLogFileSuffix
, NULL
},
242 { _T("DebugLevel"), CT_LONG
, 0, 0, 0, 0, &s_debugLevel
, &s_debugLevel
},
243 { _T("DisableIPv4"), CT_BOOLEAN
, 0, 0, AF_DISABLE_IPV4
, 0, &g_dwFlags
, NULL
},
244 { _T("DisableIPv6"), CT_BOOLEAN
, 0, 0, AF_DISABLE_IPV6
, 0, &g_dwFlags
, NULL
},
245 { _T("DumpDirectory"), CT_STRING
, 0, 0, MAX_PATH
, 0, s_dumpDir
, NULL
},
246 { _T("EnableActions"), CT_BOOLEAN
, 0, 0, AF_ENABLE_ACTIONS
, 0, &g_dwFlags
, NULL
},
247 { _T("EnabledCiphers"), CT_LONG
, 0, 0, 0, 0, &s_enabledCiphers
, NULL
},
248 { _T("EnableControlConnector"), CT_BOOLEAN
, 0, 0, AF_ENABLE_CONTROL_CONNECTOR
, 0, &g_dwFlags
, NULL
},
249 { _T("EnableProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_PROXY
, 0, &g_dwFlags
, NULL
},
250 { _T("EnableSNMPProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_SNMP_PROXY
, 0, &g_dwFlags
, NULL
},
251 { _T("EnableSNMPTrapProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_SNMP_TRAP_PROXY
, 0, &g_dwFlags
, NULL
},
252 { _T("EnableSubagentAutoload"), CT_BOOLEAN
, 0, 0, AF_ENABLE_AUTOLOAD
, 0, &g_dwFlags
, NULL
},
253 { _T("EnableWatchdog"), CT_BOOLEAN
, 0, 0, AF_ENABLE_WATCHDOG
, 0, &g_dwFlags
, NULL
},
254 { _T("EncryptedSharedSecret"), CT_STRING
, 0, 0, MAX_SECRET_LENGTH
, 0, g_szSharedSecret
, NULL
},
255 { _T("ExecTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dwExecTimeout
, NULL
},
256 { _T("ExternalMasterAgent"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_masterAgent
, NULL
},
257 { _T("ExternalParameter"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszExtParamList
, NULL
},
258 { _T("ExternalList"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszExtListsList
, NULL
},
259 { _T("ExternalParameterShellExec"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszShExtParamList
, NULL
},
260 { _T("ExternalParametersProvider"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszParamProviderList
, NULL
},
261 { _T("ExternalSubagent"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszExtSubagentList
, NULL
},
262 { _T("FileStore"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szFileStore
, NULL
},
263 { _T("FullCrashDumps"), CT_BOOLEAN
, 0, 0, AF_WRITE_FULL_DUMP
, 0, &g_dwFlags
, NULL
},
264 { _T("ListenAddress"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szListenAddress
, NULL
},
265 { _T("ListenPort"), CT_WORD
, 0, 0, 0, 0, &g_wListenPort
, NULL
},
266 { _T("LogFile"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szLogFile
, NULL
},
267 { _T("LogHistorySize"), CT_LONG
, 0, 0, 0, 0, &s_logHistorySize
, NULL
},
268 { _T("LogRotationMode"), CT_LONG
, 0, 0, 0, 0, &s_logRotationMode
, NULL
},
269 { _T("LogUnresolvedSymbols"), CT_BOOLEAN
, 0, 0, AF_LOG_UNRESOLVED_SYMBOLS
, 0, &g_dwFlags
, NULL
},
270 { _T("LongRunningQueryThreshold"), CT_LONG
, 0, 0, 0, 0, &g_longRunningQueryThreshold
, NULL
},
271 { _T("MasterServers"), CT_STRING_LIST
, ',', 0, 0, 0, &m_pszMasterServerList
, NULL
},
272 { _T("MaxLogSize"), CT_SIZE_BYTES
, 0, 0, 0, 0, &s_maxLogSize
, NULL
},
273 { _T("MaxSessions"), CT_LONG
, 0, 0, 0, 0, &g_dwMaxSessions
, NULL
},
274 { _T("PlatformSuffix"), CT_STRING
, 0, 0, MAX_PSUFFIX_LENGTH
, 0, g_szPlatformSuffix
, NULL
},
275 { _T("RequireAuthentication"), CT_BOOLEAN
, 0, 0, AF_REQUIRE_AUTH
, 0, &g_dwFlags
, NULL
},
276 { _T("RequireEncryption"), CT_BOOLEAN
, 0, 0, AF_REQUIRE_ENCRYPTION
, 0, &g_dwFlags
, NULL
},
277 { _T("Servers"), CT_STRING_LIST
, ',', 0, 0, 0, &m_pszServerList
, NULL
},
278 { _T("SessionIdleTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dwIdleTimeout
, NULL
},
279 { _T("SessionAgentPort"), CT_WORD
, 0, 0, 0, 0, &g_sessionAgentPort
, NULL
},
280 { _T("SharedSecret"), CT_STRING
, 0, 0, MAX_SECRET_LENGTH
, 0, g_szSharedSecret
, NULL
},
281 { _T("SNMPTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dwSNMPTimeout
, NULL
},
282 { _T("SNMPTrapListenAddress"), CT_STRING
, 0, 0, MAX_PATH
, 0, &g_szSNMPTrapListenAddress
, NULL
},
283 { _T("SNMPTrapPort"), CT_LONG
, 0, 0, 0, 0, &g_dwSNMPTrapPort
, NULL
},
284 { _T("StartupDelay"), CT_LONG
, 0, 0, 0, 0, &g_dwStartupDelay
, NULL
},
285 { _T("SubAgent"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszSubagentList
, NULL
},
286 { _T("TimeOut"), CT_IGNORE
, 0, 0, 0, 0, NULL
, NULL
},
287 { _T("WaitForProcess"), CT_STRING
, 0, 0, MAX_PATH
, 0, s_processToWaitFor
, NULL
},
288 { _T("ZoneId"), CT_LONG
, 0, 0, 0, 0, &g_zoneId
, NULL
},
289 { _T(""), CT_END_OF_LIST
, 0, 0, 0, 0, NULL
, NULL
}
295 static TCHAR m_szHelpText
[] =
296 _T("Usage: nxagentd [options]\n")
297 _T("Where valid options are:\n")
298 _T(" -c <file> : Use configuration file <file> (default ") AGENT_DEFAULT_CONFIG
_T(")\n")
299 _T(" -C : Load configuration file, dump resulting configuration, and exit\n")
300 _T(" -d : Run as daemon/service\n")
301 _T(" -D <level> : Set debug level (0..9)\n")
303 _T(" -e <name> : Windows event source name\n")
305 _T(" -f : Run in foreground\n")
307 _T(" -g <gid> : Chhange group ID to <gid> after start\n")
309 _T(" -h : Display help and exit\n")
311 _T(" -H : Hide agent's window when in standalone mode\n")
312 _T(" -i : Installed Windows service must be interactive\n")
313 _T(" -I : Install Windows service\n")
315 _T(" -K : Shutdown all connected external sub-agents\n")
316 _T(" -M <addr> : Download config from management server <addr>\n")
318 _T(" -n <name> : Service name\n")
319 _T(" -N <name> : Service display name\n")
322 _T(" -p : Path to pid file (default: /var/run/nxagentd.pid)\n")
324 _T(" -P <text> : Set platform suffix to <text>\n")
325 _T(" -r <addr> : Register agent on management server <addr>\n")
327 _T(" -R : Remove Windows service\n")
328 _T(" -s : Start Windows servive\n")
329 _T(" -S : Stop Windows service\n")
332 _T(" -u <uid> : Chhange user ID to <uid> after start\n")
334 _T(" -v : Display version and exit\n")
338 * Server info: constructor
340 ServerInfo::ServerInfo(const TCHAR
*name
, bool control
, bool master
)
343 m_name
= MBStringFromWideString(name
);
345 m_name
= strdup(name
);
348 char *p
= strchr(m_name
, '/');
353 m_address
= InetAddress::resolveHostName(m_name
);
354 if (m_address
.isValid())
356 int bits
= strtol(p
, NULL
, 10);
357 if ((bits
>= 0) && (bits
<= ((m_address
.getFamily() == AF_INET
) ? 32 : 128)))
358 m_address
.setMaskBits(bits
);
360 m_redoResolve
= false;
364 m_address
= InetAddress::resolveHostName(m_name
);
365 m_redoResolve
= true;
370 m_lastResolveTime
= time(NULL
);
371 m_mutex
= MutexCreate();
375 * Server info: destructor
377 ServerInfo::~ServerInfo()
380 MutexDestroy(m_mutex
);
384 * Server info: resolve hostname if needed
386 void ServerInfo::resolve()
388 time_t now
= time(NULL
);
389 time_t age
= now
- m_lastResolveTime
;
390 if ((age
>= 3600) || ((age
> 300) && !m_address
.isValid()))
392 m_address
= InetAddress::resolveHostName(m_name
);
393 m_lastResolveTime
= now
;
398 * Server info: match address
400 bool ServerInfo::match(const InetAddress
&addr
)
405 bool result
= m_address
.isValid() ? m_address
.contain(addr
) : false;
406 MutexUnlock(m_mutex
);
413 * Get our own console window handle (an alternative to Microsoft's GetConsoleWindow)
415 static HWND
GetConsoleHWND()
420 cpid
= GetCurrentProcessId();
423 hWnd
= FindWindowEx(NULL
, NULL
, _T("ConsoleWindowClass"), NULL
);
427 GetWindowThreadProcessId(hWnd
, &wpid
);
436 * Get proc address and write log file
438 static FARPROC
GetProcAddressAndLog(HMODULE hModule
, LPCSTR procName
)
442 ptr
= GetProcAddress(hModule
, procName
);
443 if ((ptr
== NULL
) && (g_dwFlags
& AF_LOG_UNRESOLVED_SYMBOLS
))
444 nxlog_write(MSG_NO_FUNCTION
, EVENTLOG_WARNING_TYPE
, "s", procName
);
449 * Shutdown thread (created by H_RestartAgent)
451 static THREAD_RESULT THREAD_CALL
ShutdownThread(void *pArg
)
453 DebugPrintf(INVALID_INDEX
, 1, _T("Shutdown thread started"));
456 return THREAD_OK
; // Never reached
465 static LONG
H_RestartAgent(const TCHAR
*action
, StringList
*args
, const TCHAR
*data
, AbstractCommSession
*session
)
467 DebugPrintf(INVALID_INDEX
, 1, _T("H_RestartAgent() called"));
469 TCHAR szCmdLine
[4096], szPlatformSuffixOption
[MAX_PSUFFIX_LENGTH
+ 16];
471 if (g_szPlatformSuffix
[0] != 0)
473 _sntprintf(szPlatformSuffixOption
, MAX_PSUFFIX_LENGTH
+ 16, _T("-P \"%s\" "), g_szPlatformSuffix
);
477 szPlatformSuffixOption
[0] = 0;
481 _sntprintf(szCmdLine
, 4096, _T("\"%s\" -c \"%s\" -n \"%s\" -e \"%s\" %s%s%s%s%s-D %d %s-X %u"), s_executableName
,
482 g_szConfigFile
, g_windowsServiceName
, g_windowsEventSourceName
,
483 (g_dwFlags
& AF_DAEMON
) ? _T("-d ") : _T(""),
484 (g_dwFlags
& AF_HIDE_WINDOW
) ? _T("-H ") : _T(""),
485 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T("-M ") : _T(""),
486 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? g_szConfigServer
: _T(""),
487 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T(" ") : _T(""),
488 s_debugLevel
, szPlatformSuffixOption
,
489 (g_dwFlags
& AF_DAEMON
) ? 0 : GetCurrentProcessId());
490 DebugPrintf(INVALID_INDEX
, 1, _T("Restarting agent with command line '%s'"), szCmdLine
);
494 PROCESS_INFORMATION pi
;
496 // Fill in process startup info structure
497 memset(&si
, 0, sizeof(STARTUPINFO
));
498 si
.cb
= sizeof(STARTUPINFO
);
500 // Create new process
501 if (!CreateProcess(NULL
, szCmdLine
, NULL
, NULL
, FALSE
,
502 (g_dwFlags
& AF_DAEMON
) ? (CREATE_NO_WINDOW
| DETACHED_PROCESS
) : (CREATE_NEW_CONSOLE
),
503 NULL
, NULL
, &si
, &pi
))
505 nxlog_write(MSG_CREATE_PROCESS_FAILED
, EVENTLOG_ERROR_TYPE
, "se", szCmdLine
, GetLastError());
506 dwResult
= ERR_EXEC_FAILED
;
511 CloseHandle(pi
.hThread
);
512 CloseHandle(pi
.hProcess
);
513 dwResult
= ERR_SUCCESS
;
515 if ((dwResult
== ERR_SUCCESS
) && (!(g_dwFlags
& AF_DAEMON
)))
517 if (g_dwFlags
& AF_HIDE_WINDOW
)
519 ConditionSet(s_shutdownCondition
);
523 ThreadCreate(ShutdownThread
, 0, NULL
);
528 _sntprintf(szCmdLine
, 4096, _T("\"%s\" -c \"%s\" %s%s%s%s-D %d %s-X %lu"), s_executableName
,
529 g_szConfigFile
, (g_dwFlags
& AF_DAEMON
) ? _T("-d ") : _T(""),
530 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T("-M ") : _T(""),
531 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? g_szConfigServer
: _T(""),
532 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T(" ") : _T(""),
533 (int)s_debugLevel
, szPlatformSuffixOption
,
534 (unsigned long)s_pid
);
535 DebugPrintf(INVALID_INDEX
, 1, _T("Restarting agent with command line '%s'"), szCmdLine
);
536 return ExecuteCommand(szCmdLine
, NULL
, NULL
);
541 * This function writes message from subagent to agent's log
543 static void WriteSubAgentMsg(int logLevel
, int debugLevel
, const TCHAR
*pszMsg
)
545 if (logLevel
== EVENTLOG_DEBUG_TYPE
)
547 if (debugLevel
<= (int)s_debugLevel
)
548 nxlog_write(MSG_DEBUG
, EVENTLOG_DEBUG_TYPE
, "s", pszMsg
);
552 nxlog_write(MSG_SUBAGENT_MSG
, logLevel
, "s", pszMsg
);
557 * Signal handler for UNIX platforms
561 static THREAD_RESULT THREAD_CALL
SignalHandler(void *pArg
)
566 sigemptyset(&signals
);
567 sigaddset(&signals
, SIGTERM
);
568 sigaddset(&signals
, SIGINT
);
569 sigaddset(&signals
, SIGSEGV
);
570 sigaddset(&signals
, SIGHUP
);
571 sigaddset(&signals
, SIGUSR1
);
572 sigaddset(&signals
, SIGUSR2
);
573 #if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
574 sigaddset(&signals
, SIGPIPE
);
577 sigprocmask(SIG_BLOCK
, &signals
, NULL
);
581 if (sigwait(&signals
, &nSignal
) == 0)
602 sigprocmask(SIG_UNBLOCK
, &signals
, NULL
);
609 * Load platform subagent
611 static void LoadPlatformSubagent()
614 LoadSubAgent(_T("WINNT.NSM"));
616 #if HAVE_SYS_UTSNAME_H && !defined(_STATIC_AGENT)
618 TCHAR szName
[MAX_PATH
];
621 if (uname(&un
) != -1)
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 _sntprintf(szName
, MAX_PATH
, _T("%hs.nsm"), un
.sysname
);
629 LoadSubAgent(szName
);
636 * Send file to server (subagent API)
638 static bool SendFileToServer(void *session
, UINT32 requestId
, const TCHAR
*file
, long offset
)
642 return ((CommSession
*)session
)->sendFile(requestId
, file
, offset
);
648 static void ParseServerList(TCHAR
*serverList
, bool isControl
, bool isMaster
)
652 for(pItem
= pEnd
= serverList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
654 pEnd
= _tcschr(pItem
, _T(','));
659 g_serverList
.add(new ServerInfo(pItem
, isControl
, isMaster
));
665 * Agent initialization
671 if (s_debugLevel
== (UINT32
)NXCONFIG_UNINITIALIZED_VALUE
)
674 if (!_tcscmp(g_szDataDirectory
, _T("{default}")))
676 GetNetXMSDirectory(nxDirData
, g_szDataDirectory
);
679 //Initialize config policy folder
680 TCHAR tail
= g_szDataDirectory
[_tcslen(g_szDataDirectory
) - 1];
681 _sntprintf(g_szConfigPolicyDir
, MAX_PATH
, _T("%s%s%s"), g_szDataDirectory
,
682 ((tail
!= '\\') && (tail
!= '/')) ? FS_PATH_SEPARATOR
: _T(""),
683 CONFIG_AP_FOLDER FS_PATH_SEPARATOR
);
684 CreateFolder(g_szConfigPolicyDir
);
686 // Load configuration
687 g_config
->loadConfigDirectory(g_szConfigPolicyDir
, _T("agent"));
688 g_config
->parseTemplate(_T("agent"), m_cfgTemplate
);
691 if (!nxlog_open((g_dwFlags
& AF_USE_SYSLOG
) ? NXAGENTD_SYSLOG_NAME
: g_szLogFile
,
692 ((g_dwFlags
& AF_USE_SYSLOG
) ? NXLOG_USE_SYSLOG
: 0) |
693 ((g_dwFlags
& AF_BACKGROUND_LOG_WRITER
) ? NXLOG_BACKGROUND_WRITER
: 0) |
694 ((g_dwFlags
& AF_DAEMON
) ? 0 : NXLOG_PRINT_TO_STDOUT
),
699 g_dwNumMessages
, g_szMessages
, MSG_DEBUG
))
702 //TODO: set flag that log have been opened with errors
704 g_failFlags
|= FAIL_OPEN_LOG
;
705 nxlog_open(NXAGENTD_SYSLOG_NAME
, NXLOG_USE_SYSLOG
|
706 ((g_dwFlags
& AF_BACKGROUND_LOG_WRITER
) ? NXLOG_BACKGROUND_WRITER
: 0) |
707 ((g_dwFlags
& AF_DAEMON
) ? 0 : NXLOG_PRINT_TO_STDOUT
),
712 g_dwNumMessages
, g_szMessages
, MSG_DEBUG
);
714 _ftprintf(stderr
, _T("ERROR: Cannot open log file, logs will be written to syslog with debug level 1\n"));
719 if (!(g_dwFlags
& AF_USE_SYSLOG
))
721 if (!nxlog_set_rotation_policy((int)s_logRotationMode
, s_maxLogSize
, (int)s_logHistorySize
, s_dailyLogFileSuffix
))
722 if (!(g_dwFlags
& AF_DAEMON
))
723 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
726 nxlog_write(MSG_USE_CONFIG_D
, NXLOG_INFO
, "s", g_szConfigIncludeDir
);
727 nxlog_write(MSG_DEBUG_LEVEL
, NXLOG_INFO
, "d", s_debugLevel
);
728 nxlog_set_debug_level(s_debugLevel
);
730 if (_tcscmp(g_masterAgent
, _T("not_set")))
732 g_dwFlags
|= AF_SUBAGENT_LOADER
;
733 DebugPrintf(INVALID_INDEX
, 1, _T("Switched to external subagent loader mode, master agent address is %s"), g_masterAgent
);
736 DebugPrintf(INVALID_INDEX
, 1, _T("Data directory: %s"), g_szDataDirectory
);
737 CreateFolder(g_szDataDirectory
);
739 //Initialize log parser policy folder
740 tail
= g_szDataDirectory
[_tcslen(g_szDataDirectory
) - 1];
741 _sntprintf(g_szLogParserDirectory
, MAX_PATH
, _T("%s%s%s"), g_szDataDirectory
,
742 ((tail
!= '\\') && (tail
!= '/')) ? FS_PATH_SEPARATOR
: _T(""),
743 LOGPARSER_AP_FOLDER FS_PATH_SEPARATOR
);
744 DebugPrintf(INVALID_INDEX
, 6, _T("Log parser policy directory: %s"), g_szLogParserDirectory
);
745 CreateFolder(g_szLogParserDirectory
);
746 DebugPrintf(INVALID_INDEX
, 6, _T("Configuration policy directory: %s"), g_szConfigPolicyDir
);
747 CreateFolder(g_szFileStore
);
751 int wrc
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
754 nxlog_write(MSG_WSASTARTUP_FAILED
, NXLOG_ERROR
, "e", wrc
);
759 // Initialize API for subagents
760 s_subAgentsStopCondition
= ConditionCreate(TRUE
);
761 InitSubAgentAPI(WriteSubAgentMsg
, SendTrap
, SendTrap
, EnumerateSessions
, FindServerSession
,
762 SendFileToServer
, PushData
, GetLocalDatabaseHandle
, s_subAgentsStopCondition
, g_szDataDirectory
);
763 DebugPrintf(INVALID_INDEX
, 1, _T("Subagent API initialized"));
765 // Initialize cryptografy
766 if (!InitCryptoLib(s_enabledCiphers
))
768 nxlog_write(MSG_INIT_CRYPTO_FAILED
, EVENTLOG_ERROR_TYPE
, "e", WSAGetLastError());
772 // Initialize libssl - it is not used by core agent
773 // but may be needed by some subagents. Allowing first load of libssl by
774 // subagent via dlopen() may lead to undesired side effects
775 #ifdef _WITH_ENCRYPTION
777 SSL_load_error_strings();
780 DBInit(MSG_DB_LIBRARY
, MSG_SQL_ERROR
);
782 if (!OpenLocalDatabase())
784 nxlog_write(MSG_LOCAL_DB_OPEN_FAILED
, NXLOG_ERROR
, NULL
);
787 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
))
789 if (g_dwFlags
& AF_ENABLE_SNMP_PROXY
)
791 g_snmpProxyThreadPool
= ThreadPoolCreate(2, 128, _T("SNMPPROXY"));
795 // Initialize built-in parameters
796 if (!InitParameterList())
799 // Parse server lists
800 if (m_pszMasterServerList
!= NULL
)
801 ParseServerList(m_pszMasterServerList
, true, true);
802 if (m_pszControlServerList
!= NULL
)
803 ParseServerList(m_pszControlServerList
, true, false);
804 if (m_pszServerList
!= NULL
)
805 ParseServerList(m_pszServerList
, false, false);
807 // Add built-in actions
808 AddAction(_T("Agent.Restart"), AGENT_ACTION_SUBAGENT
, NULL
, H_RestartAgent
, _T("CORE"), _T("Restart agent"));
810 // Load platform subagents
812 InitStaticSubagents();
814 if (g_dwFlags
& AF_ENABLE_AUTOLOAD
)
816 LoadPlatformSubagent();
820 // Wait for external process if requested
821 if (s_processToWaitFor
[0] != 0)
823 DebugPrintf(INVALID_INDEX
, 1, _T("Waiting for process %s"), s_processToWaitFor
);
824 if (!WaitForProcess(s_processToWaitFor
))
825 nxlog_write(MSG_WAITFORPROCESS_FAILED
, EVENTLOG_ERROR_TYPE
, "s", s_processToWaitFor
);
828 // Load other subagents
829 if (m_pszSubagentList
!= NULL
)
831 for(pItem
= pEnd
= m_pszSubagentList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
833 pEnd
= _tcschr(pItem
, _T('\n'));
839 free(m_pszSubagentList
);
843 if (m_pszActionList
!= NULL
)
845 for(pItem
= pEnd
= m_pszActionList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
847 pEnd
= _tcschr(pItem
, _T('\n'));
851 if (!AddActionFromConfig(pItem
, FALSE
))
852 nxlog_write(MSG_ADD_ACTION_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
854 free(m_pszActionList
);
856 if (m_pszShellActionList
!= NULL
)
858 for(pItem
= pEnd
= m_pszShellActionList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
860 pEnd
= _tcschr(pItem
, _T('\n'));
865 if (!AddActionFromConfig(pItem
, TRUE
))
866 nxlog_write(MSG_ADD_ACTION_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
868 free(m_pszShellActionList
);
871 // Parse external parameters list
872 if (m_pszExtParamList
!= NULL
)
874 for(pItem
= pEnd
= m_pszExtParamList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
876 pEnd
= _tcschr(pItem
, _T('\n'));
880 if (!AddExternalParameter(pItem
, FALSE
, FALSE
))
881 nxlog_write(MSG_ADD_EXT_PARAM_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
883 free(m_pszExtParamList
);
885 if (m_pszShExtParamList
!= NULL
)
887 for(pItem
= pEnd
= m_pszShExtParamList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
889 pEnd
= _tcschr(pItem
, _T('\n'));
893 if (!AddExternalParameter(pItem
, TRUE
, FALSE
))
894 nxlog_write(MSG_ADD_EXT_PARAM_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
896 free(m_pszShExtParamList
);
899 // Parse external lists
900 if (m_pszExtListsList
!= NULL
)
902 for(pItem
= pEnd
= m_pszExtListsList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
904 pEnd
= _tcschr(pItem
, _T('\n'));
908 if (!AddExternalParameter(pItem
, FALSE
, TRUE
))
909 nxlog_write(MSG_ADD_EXT_PARAM_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
911 free(m_pszExtListsList
);
914 // Parse external parameters providers list
915 if (m_pszParamProviderList
!= NULL
)
917 for(pItem
= pEnd
= m_pszParamProviderList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
919 pEnd
= _tcschr(pItem
, _T('\n'));
923 if (!AddParametersProvider(pItem
))
924 nxlog_write(MSG_ADD_PARAM_PROVIDER_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
926 free(m_pszParamProviderList
);
929 // Parse external subagents list
930 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
) && (m_pszExtSubagentList
!= NULL
))
932 for(pItem
= pEnd
= m_pszExtSubagentList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
934 pEnd
= _tcschr(pItem
, _T('\n'));
938 if (!AddExternalSubagent(pItem
))
939 nxlog_write(MSG_ADD_EXTERNAL_SUBAGENT_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
941 free(m_pszExtSubagentList
);
944 // Parse application agents list
945 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
) && (m_pszAppAgentList
!= NULL
))
947 for(pItem
= pEnd
= m_pszAppAgentList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
949 pEnd
= _tcschr(pItem
, _T('\n'));
953 RegisterApplicationAgent(pItem
);
955 free(m_pszAppAgentList
);
960 // If StartupDelay is greater than zero, then wait
961 if (g_dwStartupDelay
> 0)
963 if (g_dwFlags
& AF_DAEMON
)
965 ThreadSleep(g_dwStartupDelay
);
971 _tprintf(_T("XXXXXX%*s]\rWAIT ["), g_dwStartupDelay
, _T(" "));
973 for(i
= 0; i
< g_dwStartupDelay
; i
++)
976 _puttc(_T('.'), stdout
);
983 StartParamProvidersPoller();
986 g_tmAgentStartTime
= time(NULL
);
988 s_eventSenderThread
= ThreadCreateEx(TrapSender
, 0, NULL
);
990 // Start trap proxy threads(recieve and send), if trap proxy is enabled
991 if(g_dwFlags
& AF_ENABLE_SNMP_TRAP_PROXY
)
993 s_snmpTrapSenderThread
= ThreadCreateEx(SNMPTrapSender
, 0, NULL
);
994 s_snmpTrapReceiverThread
= ThreadCreateEx(SNMPTrapReceiver
, 0, NULL
);
997 if (g_dwFlags
& AF_SUBAGENT_LOADER
)
999 s_masterAgentListenerThread
= ThreadCreateEx(MasterAgentListener
, 0, NULL
);
1003 // Start network listener and session watchdog
1004 StartLocalDataCollector();
1005 s_listenerThread
= ThreadCreateEx(ListenerThread
, 0, NULL
);
1006 s_sessionWatchdogThread
= ThreadCreateEx(SessionWatchdog
, 0, NULL
);
1007 StartPushConnector();
1008 StartStorageDiscoveryConnector();
1009 StartSessionAgentConnector();
1010 if (g_dwFlags
& AF_ENABLE_CONTROL_CONNECTOR
)
1012 StartControlConnector();
1015 if (g_dwFlags
& AF_REGISTER
)
1017 RegisterOnServer(g_szRegistrar
);
1022 s_shutdownCondition
= ConditionCreate(TRUE
);
1026 // Start watchdog process
1027 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
))
1029 if (g_dwFlags
& AF_ENABLE_WATCHDOG
)
1033 // Delete file used for upgrade if exists
1034 TCHAR upgradeFileName
[MAX_PATH
];
1035 ReadRegistryAsString(_T("upgrade.file"), upgradeFileName
, MAX_PATH
, _T(""));
1036 if(upgradeFileName
[0] != 0)
1038 _tremove(upgradeFileName
);
1039 DeleteRegistryEntry(_T("upgrade.file"));
1042 //Update policy inventory according to files that exist on file system
1043 UpdatePolicyInventory();
1053 DebugPrintf(INVALID_INDEX
, 2, _T("Shutdown() called"));
1054 if (g_dwFlags
& AF_ENABLE_WATCHDOG
)
1057 g_dwFlags
|= AF_SHUTDOWN
;
1058 ConditionSet(s_subAgentsStopCondition
);
1060 if (g_dwFlags
& AF_SUBAGENT_LOADER
)
1062 // TODO: shall we inform master agent listener about shutdown?
1063 //ThreadJoin(s_masterAgentListenerThread);
1067 ShutdownLocalDataCollector();
1068 ShutdownTrapSender();
1069 ThreadJoin(s_sessionWatchdogThread
);
1070 ThreadJoin(s_listenerThread
);
1072 ThreadJoin(s_eventSenderThread
);
1073 if(g_dwFlags
& AF_ENABLE_SNMP_TRAP_PROXY
)
1075 ShutdownSNMPTrapSender();
1076 ThreadJoin(s_snmpTrapReceiverThread
);
1077 ThreadJoin(s_snmpTrapSenderThread
);
1080 DestroySessionList();
1081 MsgWaitQueue::shutdown();
1083 if (g_dwFlags
& AF_ENABLE_SNMP_PROXY
)
1085 ThreadPoolDestroy(g_snmpProxyThreadPool
);
1088 UnloadAllSubAgents();
1089 CloseLocalDatabase();
1090 nxlog_write(MSG_AGENT_STOPPED
, EVENTLOG_INFORMATION_TYPE
, NULL
);
1095 // Notify main thread about shutdown
1097 ConditionSet(s_shutdownCondition
);
1101 #if !defined(_WIN32)
1102 _tremove(g_szPidFile
);
1111 nxlog_write(MSG_AGENT_STARTED
, NXLOG_INFO
, NULL
);
1113 if (g_dwFlags
& AF_DAEMON
)
1116 ConditionWait(s_shutdownCondition
, INFINITE
);
1118 StartMainLoop(SignalHandler
, NULL
);
1124 if (g_dwFlags
& AF_HIDE_WINDOW
)
1128 hWnd
= GetConsoleHWND();
1130 ShowWindow(hWnd
, SW_HIDE
);
1131 ConditionWait(s_shutdownCondition
, INFINITE
);
1136 _tprintf(_T("Agent running. Press ESC to shutdown.\n"));
1142 _tprintf(_T("Agent shutting down...\n"));
1146 _tprintf(_T("Agent running. Press Ctrl+C to shutdown.\n"));
1147 StartMainLoop(SignalHandler
, NULL
);
1148 _tprintf(_T("\nStopping agent...\n"));
1154 * Do necessary actions on agent restart
1156 static void DoRestartActions(UINT32 dwOldPID
)
1163 WaitForService(SERVICE_STOPPED
);
1164 StartAgentService();
1171 hProcess
= OpenProcess(SYNCHRONIZE
| PROCESS_TERMINATE
, FALSE
, dwOldPID
);
1172 if (hProcess
!= NULL
)
1174 if (WaitForSingleObject(hProcess
, 60000) == WAIT_TIMEOUT
)
1176 TerminateProcess(hProcess
, 0);
1178 CloseHandle(hProcess
);
1184 kill(dwOldPID
, SIGTERM
);
1185 for(i
= 0; i
< 30; i
++)
1188 if (kill(dwOldPID
, SIGCONT
) == -1)
1192 // Kill previous instance of agent if it's still running
1194 kill(dwOldPID
, SIGKILL
);
1199 * Create configuration file
1201 static int CreateConfig(const char *pszServer
, const char *pszLogFile
, const char *pszFileStore
,
1202 const char *configIncludeDir
, int iNumSubAgents
, char **ppszSubAgentList
)
1208 if (_taccess(g_szConfigFile
, 0) == 0)
1209 return 0; // File already exist, we shouldn't overwrite it
1211 fp
= _tfopen(g_szConfigFile
, _T("w"));
1214 currTime
= time(NULL
);
1215 _ftprintf(fp
, _T("#\n# NetXMS agent configuration file\n# Created by agent installer at %s#\n\n"),
1216 _tctime(&currTime
));
1217 _ftprintf(fp
, _T("MasterServers = %hs\nConfigIncludeDir = %hs\nLogFile = %hs\nFileStore = %hs\n"),
1218 pszServer
, configIncludeDir
, pszLogFile
, pszFileStore
);
1219 for(i
= 0; i
< iNumSubAgents
; i
++)
1220 _ftprintf(fp
, _T("SubAgent = %hs\n"), ppszSubAgentList
[i
]);
1223 return (fp
!= NULL
) ? 0 : 2;
1229 static void InitConfig()
1231 g_config
= new Config();
1232 g_config
->setTopLevelTag(_T("config"));
1234 // Set default data directory on Windows
1236 if (SHGetFolderPath(NULL
, CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, g_szDataDirectory
) == S_OK
)
1238 _tcscat(g_szDataDirectory
, _T("\\nxagentd"));
1244 * Initiate shutdown of connected external subagents
1246 static void InitiateExtSubagentShutdown()
1249 msg
.setCode(CMD_SHUTDOWN
);
1250 if (SendControlMessage(&msg
))
1251 _tprintf(_T("Control message sent successfully to master agent\n"));
1253 _tprintf(_T("ERROR: Unable to send control message to master agent\n"));
1261 static int GetUserId(char *name
)
1264 int id
= (int)strtol(name
, &eptr
, 10);
1269 struct passwd
*p
= getpwnam(name
);
1272 _tprintf(_T("Invalid user ID \"%hs\"\n"), name
);
1277 _tprintf(_T("Invalid user ID \"%hs\"\n"), name
);
1285 static int GetGroupId(char *name
)
1288 int id
= (int)strtol(name
, &eptr
, 10);
1293 struct group
*g
= getgrnam(name
);
1296 _tprintf(_T("Invalid group ID \"%hs\"\n"), name
);
1301 _tprintf(_T("Invalid group ID \"%hs\"\n"), name
);
1309 * Application entry point
1311 int main(int argc
, char *argv
[])
1313 int ch
, iExitCode
= 0, iAction
= ACTION_RUN_AGENT
;
1314 BOOL bRestart
= FALSE
;
1315 UINT32 dwOldPID
, dwMainPID
;
1318 TCHAR szModuleName
[MAX_PATH
];
1323 int uid
= 0, gid
= 0;
1326 InitNetXMSProcess();
1328 #if defined(__sun) || defined(_AIX) || defined(__hpux)
1329 signal(SIGPIPE
, SIG_IGN
);
1330 signal(SIGHUP
, SIG_IGN
);
1331 signal(SIGQUIT
, SIG_IGN
);
1332 signal(SIGUSR1
, SIG_IGN
);
1333 signal(SIGUSR2
, SIG_IGN
);
1336 // Check for alternate config file location
1338 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, _T("Software\\NetXMS\\Agent"), 0, KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
1340 dwSize
= MAX_PATH
* sizeof(TCHAR
);
1341 RegQueryValueEx(hKey
, _T("ConfigFile"), NULL
, NULL
, (BYTE
*)g_szConfigFile
, &dwSize
);
1342 dwSize
= MAX_PATH
* sizeof(TCHAR
);
1343 RegQueryValueEx(hKey
, _T("ConfigIncludeDir"), NULL
, NULL
, (BYTE
*)g_szConfigIncludeDir
, &dwSize
);
1347 pszEnv
= _tgetenv(_T("NXAGENTD_CONFIG"));
1349 nx_strncpy(g_szConfigFile
, pszEnv
, MAX_PATH
);
1351 pszEnv
= _tgetenv(_T("NXAGENTD_CONFIG_D"));
1353 nx_strncpy(g_szConfigIncludeDir
, pszEnv
, MAX_PATH
);
1356 // Parse command line
1358 iAction
= ACTION_HELP
;
1360 while((ch
= getopt(argc
, argv
, VALID_OPTIONS
)) != -1)
1364 case 'c': // Configuration file
1366 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szConfigFile
, MAX_PATH
);
1367 g_szConfigFile
[MAX_PATH
- 1] = 0;
1369 nx_strncpy(g_szConfigFile
, optarg
, MAX_PATH
);
1372 case 'C': // Configuration check only
1373 iAction
= ACTION_CHECK_CONFIG
;
1375 case 'd': // Run as daemon
1376 g_dwFlags
|= AF_DAEMON
;
1378 case 'D': // Turn on debug output
1379 s_debugLevel
= strtoul(optarg
, &eptr
, 0);
1380 if ((*eptr
!= 0) || (s_debugLevel
> 9))
1382 fprintf(stderr
, "Invalid debug level: %s\n", optarg
);
1387 case 'f': // Run in foreground
1388 g_dwFlags
&= ~AF_DAEMON
;
1391 case 'g': // set group ID
1392 gid
= GetGroupId(optarg
);
1395 case 'h': // Display help and exit
1396 iAction
= ACTION_HELP
;
1399 case 'H': // Hide window
1400 g_dwFlags
|= AF_HIDE_WINDOW
;
1403 case 'K': // Shutdown external sub-agents
1404 iAction
= ACTION_SHUTDOWN_EXT_AGENTS
;
1407 case 'p': // PID file
1409 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szPidFile
, MAX_PATH
);
1410 g_szPidFile
[MAX_PATH
- 1] = 0;
1412 nx_strncpy(g_szPidFile
, optarg
, MAX_PATH
);
1417 g_dwFlags
|= AF_CENTRAL_CONFIG
;
1419 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szConfigServer
, MAX_DB_STRING
);
1420 g_szConfigServer
[MAX_DB_STRING
- 1] = 0;
1422 nx_strncpy(g_szConfigServer
, optarg
, MAX_DB_STRING
);
1426 g_dwFlags
|= AF_REGISTER
;
1428 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szRegistrar
, MAX_DB_STRING
);
1429 g_szRegistrar
[MAX_DB_STRING
- 1] = 0;
1431 nx_strncpy(g_szRegistrar
, optarg
, MAX_DB_STRING
);
1434 case 'P': // Platform suffix
1436 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szPlatformSuffix
, MAX_PSUFFIX_LENGTH
);
1437 g_szPlatformSuffix
[MAX_PSUFFIX_LENGTH
- 1] = 0;
1439 nx_strncpy(g_szPlatformSuffix
, optarg
, MAX_PSUFFIX_LENGTH
);
1443 case 'u': // set user ID
1444 uid
= GetUserId(optarg
);
1447 case 'v': // Print version and exit
1448 _tprintf(_T("NetXMS Core Agent Version ") AGENT_VERSION_STRING
_T(" Build ") NETXMS_VERSION_BUILD_STRING
_T(" (") NETXMS_BUILD_TAG
_T(")") IS_UNICODE_BUILD_STRING
_T("\n"));
1449 iAction
= ACTION_NONE
;
1451 case 'W': // Watchdog process
1452 iAction
= ACTION_RUN_WATCHDOG
;
1453 dwMainPID
= strtoul(optarg
, NULL
, 10);
1455 case 'X': // Agent is being restarted
1457 dwOldPID
= strtoul(optarg
, NULL
, 10);
1459 case 'Z': // Create configuration file
1460 iAction
= ACTION_CREATE_CONFIG
;
1462 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szConfigFile
, MAX_PATH
);
1463 g_szConfigFile
[MAX_PATH
- 1] = 0;
1465 nx_strncpy(g_szConfigFile
, optarg
, MAX_PATH
);
1470 g_dwFlags
|= AF_INTERACTIVE_SERVICE
;
1472 case 'I': // Install Windows service
1473 iAction
= ACTION_INSTALL_SERVICE
;
1475 case 'R': // Remove Windows service
1476 iAction
= ACTION_REMOVE_SERVICE
;
1478 case 's': // Start Windows service
1479 iAction
= ACTION_START_SERVICE
;
1481 case 'S': // Stop Windows service
1482 iAction
= ACTION_STOP_SERVICE
;
1484 case 'E': // Install Windows event source
1485 iAction
= ACTION_INSTALL_EVENT_SOURCE
;
1487 case 'U': // Remove Windows event source
1488 iAction
= ACTION_REMOVE_EVENT_SOURCE
;
1490 case 'e': // Event source name
1492 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_windowsEventSourceName
, MAX_PATH
);
1493 g_windowsEventSourceName
[MAX_PATH
- 1] = 0;
1495 nx_strncpy(g_windowsEventSourceName
, optarg
, MAX_PATH
);
1498 case 'n': // Service name
1500 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_windowsServiceName
, MAX_PATH
);
1501 g_windowsServiceName
[MAX_PATH
- 1] = 0;
1503 nx_strncpy(g_windowsServiceName
, optarg
, MAX_PATH
);
1506 case 'N': // Service display name
1508 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_windowsServiceDisplayName
, MAX_PATH
);
1509 g_windowsServiceDisplayName
[MAX_PATH
- 1] = 0;
1511 nx_strncpy(g_windowsServiceDisplayName
, optarg
, MAX_PATH
);
1516 iAction
= ACTION_HELP
;
1524 #if !defined(_WIN32)
1527 if (setgid(gid
) != 0)
1528 _tprintf(_T("setgid(%d) call failed (%s)\n"), gid
, _tcserror(errno
));
1532 if (setuid(uid
) != 0)
1533 _tprintf(_T("setuid(%d) call failed (%s)\n"), uid
, _tcserror(errno
));
1536 if (!_tcscmp(g_szConfigFile
, _T("{search}")))
1538 TCHAR path
[MAX_PATH
] = _T("");
1539 const TCHAR
*homeDir
= _tgetenv(_T("NETXMS_HOME"));
1540 if (homeDir
!= NULL
)
1542 _sntprintf(path
, MAX_PATH
, _T("%s/etc/nxagentd.conf"), homeDir
);
1544 if ((path
[0] != 0) && (_taccess(path
, 4) == 0))
1546 _tcscpy(g_szConfigFile
, path
);
1548 else if (_taccess(PREFIX
_T("/etc/nxagentd.conf"), 4) == 0)
1550 _tcscpy(g_szConfigFile
, PREFIX
_T("/etc/nxagentd.conf"));
1552 else if (_taccess(_T("/Database/etc/nxagentd.conf"), 4) == 0) // for ZeroShell
1554 _tcscpy(g_szConfigFile
, _T("/Database/etc/nxagentd.conf"));
1556 else if (_taccess(_T("/usr/etc/nxagentd.conf"), 4) == 0)
1558 _tcscpy(g_szConfigFile
, _T("/usr/etc/nxagentd.conf"));
1562 _tcscpy(g_szConfigFile
, _T("/etc/nxagentd.conf"));
1565 if (!_tcscmp(g_szConfigIncludeDir
, _T("{search}")))
1567 TCHAR path
[MAX_PATH
] = _T("");
1568 const TCHAR
*homeDir
= _tgetenv(_T("NETXMS_HOME"));
1569 if (homeDir
!= NULL
)
1571 _sntprintf(path
, MAX_PATH
, _T("%s/etc/nxagentd.conf.d"), homeDir
);
1573 if ((path
[0] != 0) && (_taccess(path
, 4) == 0))
1575 _tcscpy(g_szConfigIncludeDir
, path
);
1577 else if (_taccess(PREFIX
_T("/etc/nxagentd.conf.d"), 4) == 0)
1579 _tcscpy(g_szConfigIncludeDir
, PREFIX
_T("/etc/nxagentd.conf.d"));
1581 else if (_taccess(_T("/Database/etc/nxagentd.conf.d"), 4) == 0)
1583 _tcscpy(g_szConfigIncludeDir
, _T("/Database/etc/nxagentd.conf.d"));
1585 else if (_taccess(_T("/usr/etc/nxagentd.conf.d"), 4) == 0)
1587 _tcscpy(g_szConfigIncludeDir
, _T("/usr/etc/nxagentd.conf.d"));
1591 _tcscpy(g_szConfigIncludeDir
, _T("/etc/nxagentd.conf.d"));
1595 if (!_tcscmp(g_szConfigFile
, _T("{search}")))
1597 TCHAR path
[MAX_PATH
];
1598 GetNetXMSDirectory(nxDirEtc
, path
);
1599 _tcscat(path
, _T("\\nxagentd.conf"));
1600 if (_taccess(path
, 4) == 0)
1602 _tcscpy(g_szConfigFile
, path
);
1606 _tcscpy(g_szConfigFile
, _T("C:\\nxagentd.conf"));
1609 if (!_tcscmp(g_szConfigIncludeDir
, _T("{search}")))
1611 TCHAR path
[MAX_PATH
];
1612 GetNetXMSDirectory(nxDirEtc
, path
);
1613 _tcscat(path
, _T("\\nxagentd.conf.d"));
1614 if (_taccess(path
, 4) == 0)
1616 _tcscpy(g_szConfigIncludeDir
, path
);
1620 _tcscpy(g_szConfigIncludeDir
, _T("C:\\nxagentd.conf.d"));
1626 DoRestartActions(dwOldPID
);
1630 // Do requested action
1633 case ACTION_RUN_AGENT
:
1634 // Set default value for session idle timeout based on
1635 // connect() timeout, if possible
1636 #if HAVE_SYSCTLBYNAME && !defined(_IPSO)
1641 nSize
= sizeof(nVal
);
1642 if (sysctlbyname("net.inet.tcp.keepinit", &nVal
, &nSize
, NULL
, 0) == 0)
1644 g_dwIdleTimeout
= nVal
/ 1000 + 15;
1649 if (g_dwFlags
& AF_CENTRAL_CONFIG
)
1651 if (s_debugLevel
> 0)
1652 _tprintf(_T("Downloading configuration from %s...\n"), g_szConfigServer
);
1653 if (DownloadConfig(g_szConfigServer
))
1655 if (s_debugLevel
> 0)
1656 _tprintf(_T("Configuration downloaded successfully\n"));
1660 if (s_debugLevel
> 0)
1661 _tprintf(_T("Configuration download failed\n"));
1665 if (g_config
->loadConfig(g_szConfigFile
, _T("agent")))
1667 const TCHAR
*dir
= g_config
->getValue(_T("/agent/ConfigIncludeDir"));
1669 nx_strncpy(g_szConfigIncludeDir
, dir
, MAX_PATH
);
1670 g_config
->loadConfigDirectory(g_szConfigIncludeDir
, _T("agent"));
1671 if (g_config
->parseTemplate(_T("agent"), m_cfgTemplate
))
1673 DecryptPassword(_T("netxms"), g_szSharedSecret
, g_szSharedSecret
, MAX_SECRET_LENGTH
);
1675 // try to guess executable path
1677 GetModuleFileName(GetModuleHandle(NULL
), s_executableName
, MAX_PATH
);
1680 char __buffer
[PATH_MAX
];
1682 #define __buffer s_executableName
1684 if (realpath(argv
[0], __buffer
) == NULL
)
1687 TCHAR
*path
= _tgetenv(_T("NETXMS_HOME"));
1690 nx_strncpy(s_executableName
, path
, sizeof(s_executableName
) / sizeof(s_executableName
[0]));
1694 nx_strncpy(s_executableName
, PREFIX
, sizeof(s_executableName
) / sizeof(s_executableName
[0]));
1696 _tcsncat(s_executableName
, _T("/bin/nxagentd"), sizeof(s_executableName
) / sizeof(s_executableName
[0]));
1701 int len
= strlen(__buffer
);
1702 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, __buffer
, len
, s_executableName
, len
);
1707 // Set exception handler
1709 if (g_dwFlags
& AF_CATCH_EXCEPTIONS
)
1710 SetExceptionHandler(SEHServiceExceptionHandler
, SEHServiceExceptionDataWriter
, s_dumpDir
,
1711 _T("nxagentd"), MSG_EXCEPTION
, g_dwFlags
& AF_WRITE_FULL_DUMP
, !(g_dwFlags
& AF_DAEMON
));
1714 if ((!_tcsicmp(g_szLogFile
, _T("{syslog}"))) ||
1715 (!_tcsicmp(g_szLogFile
, _T("{eventlog}"))))
1716 g_dwFlags
|= AF_USE_SYSLOG
;
1719 if (g_dwFlags
& AF_DAEMON
)
1731 ConsolePrintf(_T("Agent initialization failed\n"));
1737 if (g_dwFlags
& AF_DAEMON
)
1739 if (daemon(0, 0) == -1)
1741 perror("Unable to setup itself as a daemon");
1753 fp
= _tfopen(g_szPidFile
, _T("w"));
1756 _ftprintf(fp
, _T("%d"), s_pid
);
1764 ConsolePrintf(_T("Agent initialization failed\n"));
1772 if (s_shutdownCondition
!= INVALID_CONDITION_HANDLE
)
1773 ConditionDestroy(s_shutdownCondition
);
1776 LIBNETXMS_EXCEPTION_HANDLER
1781 ConsolePrintf(_T("Error parsing configuration file\n"));
1787 ConsolePrintf(_T("Error loading configuration file\n"));
1791 case ACTION_CHECK_CONFIG
:
1793 bool validConfig
= g_config
->loadConfig(g_szConfigFile
, _T("agent"), false);
1796 const TCHAR
*dir
= g_config
->getValue(_T("/agent/ConfigIncludeDir"));
1799 validConfig
= g_config
->loadConfigDirectory(dir
, _T("agent"), false);
1802 ConsolePrintf(_T("Error reading additional configuration files from \"%s\"\n"), dir
);
1809 g_config
->print(stdout
);
1810 validConfig
= g_config
->parseTemplate(_T("agent"), m_cfgTemplate
);
1815 ConsolePrintf(_T("Configuration file check failed\n"));
1820 case ACTION_RUN_WATCHDOG
:
1821 iExitCode
= WatchdogMain(dwMainPID
);
1823 case ACTION_CREATE_CONFIG
:
1824 iExitCode
= CreateConfig(CHECK_NULL_A(argv
[optind
]), CHECK_NULL_A(argv
[optind
+ 1]),
1825 CHECK_NULL_A(argv
[optind
+ 2]), CHECK_NULL_A(argv
[optind
+ 3]),
1826 argc
- optind
- 4, &argv
[optind
+ 4]);
1828 case ACTION_SHUTDOWN_EXT_AGENTS
:
1829 InitiateExtSubagentShutdown();
1833 case ACTION_INSTALL_SERVICE
:
1834 GetModuleFileName(GetModuleHandle(NULL
), szModuleName
, MAX_PATH
);
1835 InstallService(szModuleName
, g_szConfigFile
, s_debugLevel
);
1837 case ACTION_REMOVE_SERVICE
:
1840 case ACTION_INSTALL_EVENT_SOURCE
:
1841 GetModuleFileName(GetModuleHandle(NULL
), szModuleName
, MAX_PATH
);
1842 InstallEventSource(szModuleName
);
1844 case ACTION_REMOVE_EVENT_SOURCE
:
1845 RemoveEventSource();
1847 case ACTION_START_SERVICE
:
1848 StartAgentService();
1850 case ACTION_STOP_SERVICE
:
1855 _fputts(m_szHelpText
, stdout
);