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 *);
66 THREAD_RESULT THREAD_CALL
SyslogReceiver(void *);
67 THREAD_RESULT THREAD_CALL
SyslogSender(void *);
69 void ShutdownTrapSender();
70 void ShutdownSNMPTrapSender();
72 void ShutdownSyslogSender();
74 void StartLocalDataCollector();
75 void ShutdownLocalDataCollector();
79 int WatchdogMain(DWORD pid
);
81 void InitSessionList();
82 void DestroySessionList();
84 BOOL
RegisterOnServer(const TCHAR
*pszServer
);
86 void UpdatePolicyInventory();
89 void InitStaticSubagents();
93 extern TCHAR g_windowsServiceName
[];
94 extern TCHAR g_windowsServiceDisplayName
[];
97 void LIBNXAGENT_EXPORTABLE
InitSubAgentAPI(void (* writeLog
)(int, int, const TCHAR
*),
98 void (* sendTrap1
)(UINT32
, const TCHAR
*, const char *, va_list),
99 void (* sendTrap2
)(UINT32
, const TCHAR
*, int, TCHAR
**),
100 bool (* enumerateSessions
)(EnumerationCallbackResult (*)(AbstractCommSession
*, void *), void*),
101 AbstractCommSession
*(* findServerSession
)(UINT64
),
102 bool (* sendFile
)(void *, UINT32
, const TCHAR
*, long),
103 bool (* pushData
)(const TCHAR
*, const TCHAR
*, UINT32
, time_t),
104 DB_HANDLE (* getLocalDatabaseHandle
)(),
105 CONDITION shutdownCondition
, const TCHAR
*dataDirectory
);
108 * Messages generated by mc.pl (for UNIX version only)
111 extern unsigned int g_dwNumMessages
;
112 extern const TCHAR
*g_szMessages
[];
116 * Valid options for getopt()
119 #define VALID_OPTIONS "c:CdD:e:EfhHiIKM:n:N:P:r:RsSUvX:W:Z:"
121 #define VALID_OPTIONS "c:CdD:fg:hKM:p:P:r:u:vX:W:Z:"
127 #define ACTION_NONE 0
128 #define ACTION_RUN_AGENT 1
129 #define ACTION_INSTALL_SERVICE 2
130 #define ACTION_REMOVE_SERVICE 3
131 #define ACTION_START_SERVICE 4
132 #define ACTION_STOP_SERVICE 5
133 #define ACTION_CHECK_CONFIG 6
134 #define ACTION_INSTALL_EVENT_SOURCE 7
135 #define ACTION_REMOVE_EVENT_SOURCE 8
136 #define ACTION_CREATE_CONFIG 9
137 #define ACTION_HELP 10
138 #define ACTION_RUN_WATCHDOG 11
139 #define ACTION_SHUTDOWN_EXT_AGENTS 12
144 UINT32 g_dwFlags
= AF_ENABLE_ACTIONS
| AF_ENABLE_AUTOLOAD
;
145 UINT32 g_failFlags
= 0;
146 TCHAR g_szLogFile
[MAX_PATH
] = AGENT_DEFAULT_LOG
;
147 TCHAR g_szSharedSecret
[MAX_SECRET_LENGTH
] = _T("admin");
148 TCHAR g_szConfigFile
[MAX_PATH
] = AGENT_DEFAULT_CONFIG
;
149 TCHAR g_szFileStore
[MAX_PATH
] = AGENT_DEFAULT_FILE_STORE
;
150 TCHAR g_szDataDirectory
[MAX_PATH
] = AGENT_DEFAULT_DATA_DIR
;
151 TCHAR g_szPlatformSuffix
[MAX_PSUFFIX_LENGTH
] = _T("");
152 TCHAR g_szConfigServer
[MAX_DB_STRING
] = _T("not_set");
153 TCHAR g_szRegistrar
[MAX_DB_STRING
] = _T("not_set");
154 TCHAR g_szListenAddress
[MAX_PATH
] = _T("*");
155 TCHAR g_szConfigIncludeDir
[MAX_PATH
] = AGENT_DEFAULT_CONFIG_D
;
156 TCHAR g_szConfigPolicyDir
[MAX_PATH
] = AGENT_DEFAULT_CONFIG_D
;
157 TCHAR g_szLogParserDirectory
[MAX_PATH
] = _T("");
158 TCHAR g_masterAgent
[MAX_PATH
] = _T("not_set");
159 TCHAR g_szSNMPTrapListenAddress
[MAX_PATH
] = _T("*");
160 UINT16 g_wListenPort
= AGENT_LISTEN_PORT
;
161 ObjectArray
<ServerInfo
> g_serverList(8, 8, true);
162 UINT32 g_dwServerCount
= 0;
163 UINT32 g_dwExecTimeout
= 2000; // External process execution timeout in milliseconds
164 UINT32 g_dwSNMPTimeout
= 1500;
165 time_t g_tmAgentStartTime
;
166 UINT32 g_dwStartupDelay
= 0;
167 UINT32 g_dwMaxSessions
= 32;
168 UINT32 g_dwSNMPTrapPort
= 162;
169 UINT32 g_longRunningQueryThreshold
= 250;
170 UINT32 g_dcReconciliationBlockSize
= 1024;
171 UINT32 g_dcReconciliationTimeout
= 15000;
172 UINT32 g_dcMaxCollectorPoolSize
= 64;
174 UINT16 g_syslogListenPort
= 514;
176 UINT16 g_sessionAgentPort
= 28180;
178 UINT16 g_sessionAgentPort
= 0;
180 Config
*g_config
= NULL
;
182 UINT32 g_dwIdleTimeout
= 60; // Session idle timeout
184 UINT32 g_dwIdleTimeout
= 120; // Session idle timeout
188 TCHAR g_szPidFile
[MAX_PATH
] = _T("/var/run/nxagentd.pid");
194 static TCHAR
*m_pszActionList
= NULL
;
195 static TCHAR
*m_pszShellActionList
= NULL
;
196 static TCHAR
*m_pszServerList
= NULL
;
197 static TCHAR
*m_pszControlServerList
= NULL
;
198 static TCHAR
*m_pszMasterServerList
= NULL
;
199 static TCHAR
*m_pszSubagentList
= NULL
;
200 static TCHAR
*m_pszExtParamList
= NULL
;
201 static TCHAR
*m_pszExtListsList
= NULL
;
202 static TCHAR
*m_pszShExtParamList
= NULL
;
203 static TCHAR
*m_pszParamProviderList
= NULL
;
204 static TCHAR
*m_pszExtSubagentList
= NULL
;
205 static TCHAR
*m_pszAppAgentList
= NULL
;
206 static UINT32 s_enabledCiphers
= 0xFFFF;
207 static THREAD s_sessionWatchdogThread
= INVALID_THREAD_HANDLE
;
208 static THREAD s_listenerThread
= INVALID_THREAD_HANDLE
;
209 static THREAD s_eventSenderThread
= INVALID_THREAD_HANDLE
;
210 static THREAD s_snmpTrapReceiverThread
= INVALID_THREAD_HANDLE
;
211 static THREAD s_snmpTrapSenderThread
= INVALID_THREAD_HANDLE
;
212 static THREAD s_syslogReceiverThread
= INVALID_THREAD_HANDLE
;
213 static THREAD s_syslogSenderThread
= INVALID_THREAD_HANDLE
;
214 static THREAD s_masterAgentListenerThread
= INVALID_THREAD_HANDLE
;
215 static TCHAR s_processToWaitFor
[MAX_PATH
] = _T("");
216 static TCHAR s_dumpDir
[MAX_PATH
] = _T("C:\\");
217 static UINT64 s_maxLogSize
= 16384 * 1024;
218 static UINT32 s_logHistorySize
= 4;
219 static UINT32 s_logRotationMode
= NXLOG_ROTATION_BY_SIZE
;
220 static TCHAR s_dailyLogFileSuffix
[64] = _T("");
221 static TCHAR s_executableName
[MAX_PATH
];
222 static UINT32 s_debugLevel
= (UINT32
)NXCONFIG_UNINITIALIZED_VALUE
;
224 static CONDITION s_subAgentsStopCondition
= INVALID_CONDITION_HANDLE
;
226 static CONDITION s_shutdownCondition
= INVALID_CONDITION_HANDLE
;
234 * Configuration file template
236 static NX_CFG_TEMPLATE m_cfgTemplate
[] =
238 { _T("Action"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszActionList
, NULL
},
239 { _T("ActionShellExec"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszShellActionList
, NULL
},
240 { _T("AppAgent"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszAppAgentList
, NULL
},
241 { _T("BackgroundLogWriter"), CT_BOOLEAN
, 0, 0, AF_BACKGROUND_LOG_WRITER
, 0, &g_dwFlags
, NULL
},
242 { _T("ControlServers"), CT_STRING_LIST
, ',', 0, 0, 0, &m_pszControlServerList
, NULL
},
243 { _T("CreateCrashDumps"), CT_BOOLEAN
, 0, 0, AF_CATCH_EXCEPTIONS
, 0, &g_dwFlags
, NULL
},
244 { _T("DataCollectionThreadPoolSize"), CT_LONG
, 0, 0, 0, 0, &g_dcMaxCollectorPoolSize
, NULL
},
245 { _T("DataDirectory"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szDataDirectory
, NULL
},
246 { _T("DataReconciliationBlockSize"), CT_LONG
, 0, 0, 0, 0, &g_dcReconciliationBlockSize
, NULL
},
247 { _T("DataReconciliationTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dcReconciliationTimeout
, NULL
},
248 { _T("DailyLogFileSuffix"), CT_STRING
, 0, 0, 64, 0, s_dailyLogFileSuffix
, NULL
},
249 { _T("DebugLevel"), CT_LONG
, 0, 0, 0, 0, &s_debugLevel
, &s_debugLevel
},
250 { _T("DisableIPv4"), CT_BOOLEAN
, 0, 0, AF_DISABLE_IPV4
, 0, &g_dwFlags
, NULL
},
251 { _T("DisableIPv6"), CT_BOOLEAN
, 0, 0, AF_DISABLE_IPV6
, 0, &g_dwFlags
, NULL
},
252 { _T("DumpDirectory"), CT_STRING
, 0, 0, MAX_PATH
, 0, s_dumpDir
, NULL
},
253 { _T("EnableActions"), CT_BOOLEAN
, 0, 0, AF_ENABLE_ACTIONS
, 0, &g_dwFlags
, NULL
},
254 { _T("EnabledCiphers"), CT_LONG
, 0, 0, 0, 0, &s_enabledCiphers
, NULL
},
255 { _T("EnableControlConnector"), CT_BOOLEAN
, 0, 0, AF_ENABLE_CONTROL_CONNECTOR
, 0, &g_dwFlags
, NULL
},
256 { _T("EnableProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_PROXY
, 0, &g_dwFlags
, NULL
},
257 { _T("EnableSNMPProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_SNMP_PROXY
, 0, &g_dwFlags
, NULL
},
258 { _T("EnableSNMPTrapProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_SNMP_TRAP_PROXY
, 0, &g_dwFlags
, NULL
},
259 { _T("EnableSyslogProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_SYSLOG_PROXY
, 0, &g_dwFlags
, NULL
},
260 { _T("EnableSubagentAutoload"), CT_BOOLEAN
, 0, 0, AF_ENABLE_AUTOLOAD
, 0, &g_dwFlags
, NULL
},
261 { _T("EnableWatchdog"), CT_BOOLEAN
, 0, 0, AF_ENABLE_WATCHDOG
, 0, &g_dwFlags
, NULL
},
262 { _T("EncryptedSharedSecret"), CT_STRING
, 0, 0, MAX_SECRET_LENGTH
, 0, g_szSharedSecret
, NULL
},
263 { _T("ExecTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dwExecTimeout
, NULL
},
264 { _T("ExternalMasterAgent"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_masterAgent
, NULL
},
265 { _T("ExternalParameter"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszExtParamList
, NULL
},
266 { _T("ExternalList"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszExtListsList
, NULL
},
267 { _T("ExternalParameterShellExec"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszShExtParamList
, NULL
},
268 { _T("ExternalParametersProvider"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszParamProviderList
, NULL
},
269 { _T("ExternalSubagent"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszExtSubagentList
, NULL
},
270 { _T("FileStore"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szFileStore
, NULL
},
271 { _T("FullCrashDumps"), CT_BOOLEAN
, 0, 0, AF_WRITE_FULL_DUMP
, 0, &g_dwFlags
, NULL
},
272 { _T("ListenAddress"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szListenAddress
, NULL
},
273 { _T("ListenPort"), CT_WORD
, 0, 0, 0, 0, &g_wListenPort
, NULL
},
274 { _T("LogFile"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szLogFile
, NULL
},
275 { _T("LogHistorySize"), CT_LONG
, 0, 0, 0, 0, &s_logHistorySize
, NULL
},
276 { _T("LogRotationMode"), CT_LONG
, 0, 0, 0, 0, &s_logRotationMode
, NULL
},
277 { _T("LogUnresolvedSymbols"), CT_BOOLEAN
, 0, 0, AF_LOG_UNRESOLVED_SYMBOLS
, 0, &g_dwFlags
, NULL
},
278 { _T("LongRunningQueryThreshold"), CT_LONG
, 0, 0, 0, 0, &g_longRunningQueryThreshold
, NULL
},
279 { _T("MasterServers"), CT_STRING_LIST
, ',', 0, 0, 0, &m_pszMasterServerList
, NULL
},
280 { _T("MaxLogSize"), CT_SIZE_BYTES
, 0, 0, 0, 0, &s_maxLogSize
, NULL
},
281 { _T("MaxSessions"), CT_LONG
, 0, 0, 0, 0, &g_dwMaxSessions
, NULL
},
282 { _T("PlatformSuffix"), CT_STRING
, 0, 0, MAX_PSUFFIX_LENGTH
, 0, g_szPlatformSuffix
, NULL
},
283 { _T("RequireAuthentication"), CT_BOOLEAN
, 0, 0, AF_REQUIRE_AUTH
, 0, &g_dwFlags
, NULL
},
284 { _T("RequireEncryption"), CT_BOOLEAN
, 0, 0, AF_REQUIRE_ENCRYPTION
, 0, &g_dwFlags
, NULL
},
285 { _T("Servers"), CT_STRING_LIST
, ',', 0, 0, 0, &m_pszServerList
, NULL
},
286 { _T("SessionIdleTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dwIdleTimeout
, NULL
},
287 { _T("SessionAgentPort"), CT_WORD
, 0, 0, 0, 0, &g_sessionAgentPort
, NULL
},
288 { _T("SharedSecret"), CT_STRING
, 0, 0, MAX_SECRET_LENGTH
, 0, g_szSharedSecret
, NULL
},
289 { _T("SNMPTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dwSNMPTimeout
, NULL
},
290 { _T("SNMPTrapListenAddress"), CT_STRING
, 0, 0, MAX_PATH
, 0, &g_szSNMPTrapListenAddress
, NULL
},
291 { _T("SNMPTrapPort"), CT_LONG
, 0, 0, 0, 0, &g_dwSNMPTrapPort
, NULL
},
292 { _T("StartupDelay"), CT_LONG
, 0, 0, 0, 0, &g_dwStartupDelay
, NULL
},
293 { _T("SubAgent"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszSubagentList
, NULL
},
294 { _T("SyslogListenPort"), CT_WORD
, 0, 0, 0, 0, &g_syslogListenPort
, NULL
},
295 { _T("TimeOut"), CT_IGNORE
, 0, 0, 0, 0, NULL
, NULL
},
296 { _T("WaitForProcess"), CT_STRING
, 0, 0, MAX_PATH
, 0, s_processToWaitFor
, NULL
},
297 { _T("ZoneId"), CT_LONG
, 0, 0, 0, 0, &g_zoneId
, NULL
},
298 { _T(""), CT_END_OF_LIST
, 0, 0, 0, 0, NULL
, NULL
}
304 static TCHAR m_szHelpText
[] =
305 _T("Usage: nxagentd [options]\n")
306 _T("Where valid options are:\n")
307 _T(" -c <file> : Use configuration file <file> (default ") AGENT_DEFAULT_CONFIG
_T(")\n")
308 _T(" -C : Load configuration file, dump resulting configuration, and exit\n")
309 _T(" -d : Run as daemon/service\n")
310 _T(" -D <level> : Set debug level (0..9)\n")
312 _T(" -e <name> : Windows event source name\n")
314 _T(" -f : Run in foreground\n")
316 _T(" -g <gid> : Chhange group ID to <gid> after start\n")
318 _T(" -h : Display help and exit\n")
320 _T(" -H : Hide agent's window when in standalone mode\n")
321 _T(" -i : Installed Windows service must be interactive\n")
322 _T(" -I : Install Windows service\n")
324 _T(" -K : Shutdown all connected external sub-agents\n")
325 _T(" -M <addr> : Download config from management server <addr>\n")
327 _T(" -n <name> : Service name\n")
328 _T(" -N <name> : Service display name\n")
331 _T(" -p : Path to pid file (default: /var/run/nxagentd.pid)\n")
333 _T(" -P <text> : Set platform suffix to <text>\n")
334 _T(" -r <addr> : Register agent on management server <addr>\n")
336 _T(" -R : Remove Windows service\n")
337 _T(" -s : Start Windows servive\n")
338 _T(" -S : Stop Windows service\n")
341 _T(" -u <uid> : Chhange user ID to <uid> after start\n")
343 _T(" -v : Display version and exit\n")
347 * Server info: constructor
349 ServerInfo::ServerInfo(const TCHAR
*name
, bool control
, bool master
)
352 m_name
= MBStringFromWideString(name
);
354 m_name
= strdup(name
);
357 char *p
= strchr(m_name
, '/');
362 m_address
= InetAddress::resolveHostName(m_name
);
363 if (m_address
.isValid())
365 int bits
= strtol(p
, NULL
, 10);
366 if ((bits
>= 0) && (bits
<= ((m_address
.getFamily() == AF_INET
) ? 32 : 128)))
367 m_address
.setMaskBits(bits
);
369 m_redoResolve
= false;
373 m_address
= InetAddress::resolveHostName(m_name
);
374 m_redoResolve
= true;
379 m_lastResolveTime
= time(NULL
);
380 m_mutex
= MutexCreate();
384 * Server info: destructor
386 ServerInfo::~ServerInfo()
389 MutexDestroy(m_mutex
);
393 * Server info: resolve hostname if needed
395 void ServerInfo::resolve()
397 time_t now
= time(NULL
);
398 time_t age
= now
- m_lastResolveTime
;
399 if ((age
>= 3600) || ((age
> 300) && !m_address
.isValid()))
401 m_address
= InetAddress::resolveHostName(m_name
);
402 m_lastResolveTime
= now
;
407 * Server info: match address
409 bool ServerInfo::match(const InetAddress
&addr
)
414 bool result
= m_address
.isValid() ? m_address
.contain(addr
) : false;
415 MutexUnlock(m_mutex
);
422 * Get our own console window handle (an alternative to Microsoft's GetConsoleWindow)
424 static HWND
GetConsoleHWND()
429 cpid
= GetCurrentProcessId();
432 hWnd
= FindWindowEx(NULL
, NULL
, _T("ConsoleWindowClass"), NULL
);
436 GetWindowThreadProcessId(hWnd
, &wpid
);
445 * Get proc address and write log file
447 static FARPROC
GetProcAddressAndLog(HMODULE hModule
, LPCSTR procName
)
451 ptr
= GetProcAddress(hModule
, procName
);
452 if ((ptr
== NULL
) && (g_dwFlags
& AF_LOG_UNRESOLVED_SYMBOLS
))
453 nxlog_write(MSG_NO_FUNCTION
, EVENTLOG_WARNING_TYPE
, "s", procName
);
458 * Shutdown thread (created by H_RestartAgent)
460 static THREAD_RESULT THREAD_CALL
ShutdownThread(void *pArg
)
462 DebugPrintf(INVALID_INDEX
, 1, _T("Shutdown thread started"));
465 return THREAD_OK
; // Never reached
474 static LONG
H_RestartAgent(const TCHAR
*action
, StringList
*args
, const TCHAR
*data
, AbstractCommSession
*session
)
476 DebugPrintf(INVALID_INDEX
, 1, _T("H_RestartAgent() called"));
478 TCHAR szCmdLine
[4096], szPlatformSuffixOption
[MAX_PSUFFIX_LENGTH
+ 16];
480 if (g_szPlatformSuffix
[0] != 0)
482 _sntprintf(szPlatformSuffixOption
, MAX_PSUFFIX_LENGTH
+ 16, _T("-P \"%s\" "), g_szPlatformSuffix
);
486 szPlatformSuffixOption
[0] = 0;
490 _sntprintf(szCmdLine
, 4096, _T("\"%s\" -c \"%s\" -n \"%s\" -e \"%s\" %s%s%s%s%s-D %d %s-X %u"), s_executableName
,
491 g_szConfigFile
, g_windowsServiceName
, g_windowsEventSourceName
,
492 (g_dwFlags
& AF_DAEMON
) ? _T("-d ") : _T(""),
493 (g_dwFlags
& AF_HIDE_WINDOW
) ? _T("-H ") : _T(""),
494 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T("-M ") : _T(""),
495 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? g_szConfigServer
: _T(""),
496 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T(" ") : _T(""),
497 s_debugLevel
, szPlatformSuffixOption
,
498 (g_dwFlags
& AF_DAEMON
) ? 0 : GetCurrentProcessId());
499 DebugPrintf(INVALID_INDEX
, 1, _T("Restarting agent with command line '%s'"), szCmdLine
);
503 PROCESS_INFORMATION pi
;
505 // Fill in process startup info structure
506 memset(&si
, 0, sizeof(STARTUPINFO
));
507 si
.cb
= sizeof(STARTUPINFO
);
509 // Create new process
510 if (!CreateProcess(NULL
, szCmdLine
, NULL
, NULL
, FALSE
,
511 (g_dwFlags
& AF_DAEMON
) ? (CREATE_NO_WINDOW
| DETACHED_PROCESS
) : (CREATE_NEW_CONSOLE
),
512 NULL
, NULL
, &si
, &pi
))
514 nxlog_write(MSG_CREATE_PROCESS_FAILED
, EVENTLOG_ERROR_TYPE
, "se", szCmdLine
, GetLastError());
515 dwResult
= ERR_EXEC_FAILED
;
520 CloseHandle(pi
.hThread
);
521 CloseHandle(pi
.hProcess
);
522 dwResult
= ERR_SUCCESS
;
524 if ((dwResult
== ERR_SUCCESS
) && (!(g_dwFlags
& AF_DAEMON
)))
526 if (g_dwFlags
& AF_HIDE_WINDOW
)
528 ConditionSet(s_shutdownCondition
);
532 ThreadCreate(ShutdownThread
, 0, NULL
);
537 _sntprintf(szCmdLine
, 4096, _T("\"%s\" -c \"%s\" %s%s%s%s-D %d %s-X %lu"), s_executableName
,
538 g_szConfigFile
, (g_dwFlags
& AF_DAEMON
) ? _T("-d ") : _T(""),
539 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T("-M ") : _T(""),
540 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? g_szConfigServer
: _T(""),
541 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T(" ") : _T(""),
542 (int)s_debugLevel
, szPlatformSuffixOption
,
543 (unsigned long)s_pid
);
544 DebugPrintf(INVALID_INDEX
, 1, _T("Restarting agent with command line '%s'"), szCmdLine
);
545 return ExecuteCommand(szCmdLine
, NULL
, NULL
);
550 * This function writes message from subagent to agent's log
552 static void WriteSubAgentMsg(int logLevel
, int debugLevel
, const TCHAR
*pszMsg
)
554 if (logLevel
== EVENTLOG_DEBUG_TYPE
)
556 if (debugLevel
<= (int)s_debugLevel
)
557 nxlog_write(MSG_DEBUG
, EVENTLOG_DEBUG_TYPE
, "s", pszMsg
);
561 nxlog_write(MSG_SUBAGENT_MSG
, logLevel
, "s", pszMsg
);
566 * Signal handler for UNIX platforms
570 static THREAD_RESULT THREAD_CALL
SignalHandler(void *pArg
)
575 sigemptyset(&signals
);
576 sigaddset(&signals
, SIGTERM
);
577 sigaddset(&signals
, SIGINT
);
578 sigaddset(&signals
, SIGSEGV
);
579 sigaddset(&signals
, SIGHUP
);
580 sigaddset(&signals
, SIGUSR1
);
581 sigaddset(&signals
, SIGUSR2
);
582 #if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
583 sigaddset(&signals
, SIGPIPE
);
586 sigprocmask(SIG_BLOCK
, &signals
, NULL
);
590 if (sigwait(&signals
, &nSignal
) == 0)
611 sigprocmask(SIG_UNBLOCK
, &signals
, NULL
);
618 * Load platform subagent
620 static void LoadPlatformSubagent()
623 LoadSubAgent(_T("WINNT.NSM"));
625 #if HAVE_SYS_UTSNAME_H && !defined(_STATIC_AGENT)
627 TCHAR szName
[MAX_PATH
];
630 if (uname(&un
) != -1)
632 // Convert system name to lowercase
633 for(i
= 0; un
.sysname
[i
] != 0; i
++)
634 un
.sysname
[i
] = tolower(un
.sysname
[i
]);
635 if (!strcmp(un
.sysname
, "hp-ux"))
636 strcpy(un
.sysname
, "hpux");
637 _sntprintf(szName
, MAX_PATH
, _T("%hs.nsm"), un
.sysname
);
638 LoadSubAgent(szName
);
645 * Send file to server (subagent API)
647 static bool SendFileToServer(void *session
, UINT32 requestId
, const TCHAR
*file
, long offset
)
651 return ((CommSession
*)session
)->sendFile(requestId
, file
, offset
);
657 static void ParseServerList(TCHAR
*serverList
, bool isControl
, bool isMaster
)
661 for(pItem
= pEnd
= serverList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
663 pEnd
= _tcschr(pItem
, _T(','));
668 g_serverList
.add(new ServerInfo(pItem
, isControl
, isMaster
));
674 * Agent initialization
680 if (s_debugLevel
== (UINT32
)NXCONFIG_UNINITIALIZED_VALUE
)
683 if (!_tcscmp(g_szDataDirectory
, _T("{default}")))
685 GetNetXMSDirectory(nxDirData
, g_szDataDirectory
);
688 //Initialize config policy folder
689 TCHAR tail
= g_szDataDirectory
[_tcslen(g_szDataDirectory
) - 1];
690 _sntprintf(g_szConfigPolicyDir
, MAX_PATH
, _T("%s%s%s"), g_szDataDirectory
,
691 ((tail
!= '\\') && (tail
!= '/')) ? FS_PATH_SEPARATOR
: _T(""),
692 CONFIG_AP_FOLDER FS_PATH_SEPARATOR
);
693 CreateFolder(g_szConfigPolicyDir
);
695 // Load configuration
696 g_config
->loadConfigDirectory(g_szConfigPolicyDir
, _T("agent"));
697 g_config
->parseTemplate(_T("agent"), m_cfgTemplate
);
700 if (!nxlog_open((g_dwFlags
& AF_USE_SYSLOG
) ? NXAGENTD_SYSLOG_NAME
: g_szLogFile
,
701 ((g_dwFlags
& AF_USE_SYSLOG
) ? NXLOG_USE_SYSLOG
: 0) |
702 ((g_dwFlags
& AF_BACKGROUND_LOG_WRITER
) ? NXLOG_BACKGROUND_WRITER
: 0) |
703 ((g_dwFlags
& AF_DAEMON
) ? 0 : NXLOG_PRINT_TO_STDOUT
),
708 g_dwNumMessages
, g_szMessages
, MSG_DEBUG
))
711 //TODO: set flag that log have been opened with errors
713 g_failFlags
|= FAIL_OPEN_LOG
;
714 nxlog_open(NXAGENTD_SYSLOG_NAME
, NXLOG_USE_SYSLOG
|
715 ((g_dwFlags
& AF_BACKGROUND_LOG_WRITER
) ? NXLOG_BACKGROUND_WRITER
: 0) |
716 ((g_dwFlags
& AF_DAEMON
) ? 0 : NXLOG_PRINT_TO_STDOUT
),
721 g_dwNumMessages
, g_szMessages
, MSG_DEBUG
);
723 _ftprintf(stderr
, _T("ERROR: Cannot open log file, logs will be written to syslog with debug level 1\n"));
728 if (!(g_dwFlags
& AF_USE_SYSLOG
))
730 if (!nxlog_set_rotation_policy((int)s_logRotationMode
, s_maxLogSize
, (int)s_logHistorySize
, s_dailyLogFileSuffix
))
731 if (!(g_dwFlags
& AF_DAEMON
))
732 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
735 nxlog_write(MSG_USE_CONFIG_D
, NXLOG_INFO
, "s", g_szConfigIncludeDir
);
736 nxlog_write(MSG_DEBUG_LEVEL
, NXLOG_INFO
, "d", s_debugLevel
);
737 nxlog_set_debug_level(s_debugLevel
);
739 if (_tcscmp(g_masterAgent
, _T("not_set")))
741 g_dwFlags
|= AF_SUBAGENT_LOADER
;
742 DebugPrintf(INVALID_INDEX
, 1, _T("Switched to external subagent loader mode, master agent address is %s"), g_masterAgent
);
745 DebugPrintf(INVALID_INDEX
, 1, _T("Data directory: %s"), g_szDataDirectory
);
746 CreateFolder(g_szDataDirectory
);
748 //Initialize log parser policy folder
749 tail
= g_szDataDirectory
[_tcslen(g_szDataDirectory
) - 1];
750 _sntprintf(g_szLogParserDirectory
, MAX_PATH
, _T("%s%s%s"), g_szDataDirectory
,
751 ((tail
!= '\\') && (tail
!= '/')) ? FS_PATH_SEPARATOR
: _T(""),
752 LOGPARSER_AP_FOLDER FS_PATH_SEPARATOR
);
753 DebugPrintf(INVALID_INDEX
, 6, _T("Log parser policy directory: %s"), g_szLogParserDirectory
);
754 CreateFolder(g_szLogParserDirectory
);
755 DebugPrintf(INVALID_INDEX
, 6, _T("Configuration policy directory: %s"), g_szConfigPolicyDir
);
756 CreateFolder(g_szFileStore
);
760 int wrc
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
763 nxlog_write(MSG_WSASTARTUP_FAILED
, NXLOG_ERROR
, "e", wrc
);
768 // Initialize API for subagents
769 s_subAgentsStopCondition
= ConditionCreate(TRUE
);
770 InitSubAgentAPI(WriteSubAgentMsg
, SendTrap
, SendTrap
, EnumerateSessions
, FindServerSession
,
771 SendFileToServer
, PushData
, GetLocalDatabaseHandle
, s_subAgentsStopCondition
, g_szDataDirectory
);
772 DebugPrintf(INVALID_INDEX
, 1, _T("Subagent API initialized"));
774 // Initialize cryptografy
775 if (!InitCryptoLib(s_enabledCiphers
))
777 nxlog_write(MSG_INIT_CRYPTO_FAILED
, EVENTLOG_ERROR_TYPE
, "e", WSAGetLastError());
781 // Initialize libssl - it is not used by core agent
782 // but may be needed by some subagents. Allowing first load of libssl by
783 // subagent via dlopen() may lead to undesired side effects
784 #ifdef _WITH_ENCRYPTION
786 SSL_load_error_strings();
789 DBInit(MSG_DB_LIBRARY
, MSG_SQL_ERROR
);
791 if (!OpenLocalDatabase())
793 nxlog_write(MSG_LOCAL_DB_OPEN_FAILED
, NXLOG_ERROR
, NULL
);
796 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
))
798 if (g_dwFlags
& AF_ENABLE_SNMP_PROXY
)
800 g_snmpProxyThreadPool
= ThreadPoolCreate(2, 128, _T("SNMPPROXY"));
804 // Initialize built-in parameters
805 if (!InitParameterList())
808 // Parse server lists
809 if (m_pszMasterServerList
!= NULL
)
810 ParseServerList(m_pszMasterServerList
, true, true);
811 if (m_pszControlServerList
!= NULL
)
812 ParseServerList(m_pszControlServerList
, true, false);
813 if (m_pszServerList
!= NULL
)
814 ParseServerList(m_pszServerList
, false, false);
816 // Add built-in actions
817 AddAction(_T("Agent.Restart"), AGENT_ACTION_SUBAGENT
, NULL
, H_RestartAgent
, _T("CORE"), _T("Restart agent"));
819 // Load platform subagents
821 InitStaticSubagents();
823 if (g_dwFlags
& AF_ENABLE_AUTOLOAD
)
825 LoadPlatformSubagent();
829 // Wait for external process if requested
830 if (s_processToWaitFor
[0] != 0)
832 DebugPrintf(INVALID_INDEX
, 1, _T("Waiting for process %s"), s_processToWaitFor
);
833 if (!WaitForProcess(s_processToWaitFor
))
834 nxlog_write(MSG_WAITFORPROCESS_FAILED
, EVENTLOG_ERROR_TYPE
, "s", s_processToWaitFor
);
837 // Load other subagents
838 if (m_pszSubagentList
!= NULL
)
840 for(pItem
= pEnd
= m_pszSubagentList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
842 pEnd
= _tcschr(pItem
, _T('\n'));
848 free(m_pszSubagentList
);
852 if (m_pszActionList
!= NULL
)
854 for(pItem
= pEnd
= m_pszActionList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
856 pEnd
= _tcschr(pItem
, _T('\n'));
860 if (!AddActionFromConfig(pItem
, FALSE
))
861 nxlog_write(MSG_ADD_ACTION_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
863 free(m_pszActionList
);
865 if (m_pszShellActionList
!= NULL
)
867 for(pItem
= pEnd
= m_pszShellActionList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
869 pEnd
= _tcschr(pItem
, _T('\n'));
874 if (!AddActionFromConfig(pItem
, TRUE
))
875 nxlog_write(MSG_ADD_ACTION_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
877 free(m_pszShellActionList
);
880 // Parse external parameters list
881 if (m_pszExtParamList
!= NULL
)
883 for(pItem
= pEnd
= m_pszExtParamList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
885 pEnd
= _tcschr(pItem
, _T('\n'));
889 if (!AddExternalParameter(pItem
, FALSE
, FALSE
))
890 nxlog_write(MSG_ADD_EXT_PARAM_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
892 free(m_pszExtParamList
);
894 if (m_pszShExtParamList
!= NULL
)
896 for(pItem
= pEnd
= m_pszShExtParamList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
898 pEnd
= _tcschr(pItem
, _T('\n'));
902 if (!AddExternalParameter(pItem
, TRUE
, FALSE
))
903 nxlog_write(MSG_ADD_EXT_PARAM_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
905 free(m_pszShExtParamList
);
908 // Parse external lists
909 if (m_pszExtListsList
!= NULL
)
911 for(pItem
= pEnd
= m_pszExtListsList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
913 pEnd
= _tcschr(pItem
, _T('\n'));
917 if (!AddExternalParameter(pItem
, FALSE
, TRUE
))
918 nxlog_write(MSG_ADD_EXT_PARAM_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
920 free(m_pszExtListsList
);
923 // Parse external parameters providers list
924 if (m_pszParamProviderList
!= NULL
)
926 for(pItem
= pEnd
= m_pszParamProviderList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
928 pEnd
= _tcschr(pItem
, _T('\n'));
932 if (!AddParametersProvider(pItem
))
933 nxlog_write(MSG_ADD_PARAM_PROVIDER_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
935 free(m_pszParamProviderList
);
938 // Parse external subagents list
939 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
) && (m_pszExtSubagentList
!= NULL
))
941 for(pItem
= pEnd
= m_pszExtSubagentList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
943 pEnd
= _tcschr(pItem
, _T('\n'));
947 if (!AddExternalSubagent(pItem
))
948 nxlog_write(MSG_ADD_EXTERNAL_SUBAGENT_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
950 free(m_pszExtSubagentList
);
953 // Parse application agents list
954 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
) && (m_pszAppAgentList
!= NULL
))
956 for(pItem
= pEnd
= m_pszAppAgentList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
958 pEnd
= _tcschr(pItem
, _T('\n'));
962 RegisterApplicationAgent(pItem
);
964 free(m_pszAppAgentList
);
969 // If StartupDelay is greater than zero, then wait
970 if (g_dwStartupDelay
> 0)
972 if (g_dwFlags
& AF_DAEMON
)
974 ThreadSleep(g_dwStartupDelay
);
980 _tprintf(_T("XXXXXX%*s]\rWAIT ["), g_dwStartupDelay
, _T(" "));
982 for(i
= 0; i
< g_dwStartupDelay
; i
++)
985 _puttc(_T('.'), stdout
);
992 StartParamProvidersPoller();
995 g_tmAgentStartTime
= time(NULL
);
997 s_eventSenderThread
= ThreadCreateEx(TrapSender
, 0, NULL
);
999 if (g_dwFlags
& AF_ENABLE_SNMP_TRAP_PROXY
)
1001 s_snmpTrapSenderThread
= ThreadCreateEx(SNMPTrapSender
, 0, NULL
);
1002 s_snmpTrapReceiverThread
= ThreadCreateEx(SNMPTrapReceiver
, 0, NULL
);
1005 if (g_dwFlags
& AF_ENABLE_SYSLOG_PROXY
)
1007 s_syslogSenderThread
= ThreadCreateEx(SyslogSender
, 0, NULL
);
1008 s_syslogReceiverThread
= ThreadCreateEx(SyslogReceiver
, 0, NULL
);
1011 if (g_dwFlags
& AF_SUBAGENT_LOADER
)
1013 s_masterAgentListenerThread
= ThreadCreateEx(MasterAgentListener
, 0, NULL
);
1017 // Start network listener and session watchdog
1018 StartLocalDataCollector();
1019 s_listenerThread
= ThreadCreateEx(ListenerThread
, 0, NULL
);
1020 s_sessionWatchdogThread
= ThreadCreateEx(SessionWatchdog
, 0, NULL
);
1021 StartPushConnector();
1022 StartStorageDiscoveryConnector();
1023 StartSessionAgentConnector();
1024 if (g_dwFlags
& AF_ENABLE_CONTROL_CONNECTOR
)
1026 StartControlConnector();
1029 if (g_dwFlags
& AF_REGISTER
)
1031 RegisterOnServer(g_szRegistrar
);
1036 s_shutdownCondition
= ConditionCreate(TRUE
);
1040 // Start watchdog process
1041 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
))
1043 if (g_dwFlags
& AF_ENABLE_WATCHDOG
)
1047 // Delete file used for upgrade if exists
1048 TCHAR upgradeFileName
[MAX_PATH
];
1049 ReadRegistryAsString(_T("upgrade.file"), upgradeFileName
, MAX_PATH
, _T(""));
1050 if(upgradeFileName
[0] != 0)
1052 _tremove(upgradeFileName
);
1053 DeleteRegistryEntry(_T("upgrade.file"));
1056 //Update policy inventory according to files that exist on file system
1057 UpdatePolicyInventory();
1067 DebugPrintf(INVALID_INDEX
, 2, _T("Shutdown() called"));
1068 if (g_dwFlags
& AF_ENABLE_WATCHDOG
)
1071 g_dwFlags
|= AF_SHUTDOWN
;
1072 ConditionSet(s_subAgentsStopCondition
);
1074 if (g_dwFlags
& AF_SUBAGENT_LOADER
)
1076 // TODO: shall we inform master agent listener about shutdown?
1077 //ThreadJoin(s_masterAgentListenerThread);
1081 ShutdownLocalDataCollector();
1082 ShutdownTrapSender();
1083 ThreadJoin(s_sessionWatchdogThread
);
1084 ThreadJoin(s_listenerThread
);
1086 ThreadJoin(s_eventSenderThread
);
1087 if (g_dwFlags
& AF_ENABLE_SNMP_TRAP_PROXY
)
1089 ShutdownSNMPTrapSender();
1090 ThreadJoin(s_snmpTrapReceiverThread
);
1091 ThreadJoin(s_snmpTrapSenderThread
);
1093 if (g_dwFlags
& AF_ENABLE_SYSLOG_PROXY
)
1095 ShutdownSyslogSender();
1096 ThreadJoin(s_syslogReceiverThread
);
1097 ThreadJoin(s_syslogSenderThread
);
1100 DestroySessionList();
1101 MsgWaitQueue::shutdown();
1103 if (g_dwFlags
& AF_ENABLE_SNMP_PROXY
)
1105 ThreadPoolDestroy(g_snmpProxyThreadPool
);
1108 UnloadAllSubAgents();
1109 CloseLocalDatabase();
1110 nxlog_write(MSG_AGENT_STOPPED
, EVENTLOG_INFORMATION_TYPE
, NULL
);
1115 // Notify main thread about shutdown
1117 ConditionSet(s_shutdownCondition
);
1121 #if !defined(_WIN32)
1122 _tremove(g_szPidFile
);
1131 nxlog_write(MSG_AGENT_STARTED
, NXLOG_INFO
, NULL
);
1133 if (g_dwFlags
& AF_DAEMON
)
1136 ConditionWait(s_shutdownCondition
, INFINITE
);
1138 StartMainLoop(SignalHandler
, NULL
);
1144 if (g_dwFlags
& AF_HIDE_WINDOW
)
1148 hWnd
= GetConsoleHWND();
1150 ShowWindow(hWnd
, SW_HIDE
);
1151 ConditionWait(s_shutdownCondition
, INFINITE
);
1156 _tprintf(_T("Agent running. Press ESC to shutdown.\n"));
1162 _tprintf(_T("Agent shutting down...\n"));
1166 _tprintf(_T("Agent running. Press Ctrl+C to shutdown.\n"));
1167 StartMainLoop(SignalHandler
, NULL
);
1168 _tprintf(_T("\nStopping agent...\n"));
1174 * Do necessary actions on agent restart
1176 static void DoRestartActions(UINT32 dwOldPID
)
1183 WaitForService(SERVICE_STOPPED
);
1184 StartAgentService();
1191 hProcess
= OpenProcess(SYNCHRONIZE
| PROCESS_TERMINATE
, FALSE
, dwOldPID
);
1192 if (hProcess
!= NULL
)
1194 if (WaitForSingleObject(hProcess
, 60000) == WAIT_TIMEOUT
)
1196 TerminateProcess(hProcess
, 0);
1198 CloseHandle(hProcess
);
1204 kill(dwOldPID
, SIGTERM
);
1205 for(i
= 0; i
< 30; i
++)
1208 if (kill(dwOldPID
, SIGCONT
) == -1)
1212 // Kill previous instance of agent if it's still running
1214 kill(dwOldPID
, SIGKILL
);
1219 * Create configuration file
1221 static int CreateConfig(const char *pszServer
, const char *pszLogFile
, const char *pszFileStore
,
1222 const char *configIncludeDir
, int iNumSubAgents
, char **ppszSubAgentList
)
1228 if (_taccess(g_szConfigFile
, 0) == 0)
1229 return 0; // File already exist, we shouldn't overwrite it
1231 fp
= _tfopen(g_szConfigFile
, _T("w"));
1234 currTime
= time(NULL
);
1235 _ftprintf(fp
, _T("#\n# NetXMS agent configuration file\n# Created by agent installer at %s#\n\n"),
1236 _tctime(&currTime
));
1237 _ftprintf(fp
, _T("MasterServers = %hs\nConfigIncludeDir = %hs\nLogFile = %hs\nFileStore = %hs\n"),
1238 pszServer
, configIncludeDir
, pszLogFile
, pszFileStore
);
1239 for(i
= 0; i
< iNumSubAgents
; i
++)
1240 _ftprintf(fp
, _T("SubAgent = %hs\n"), ppszSubAgentList
[i
]);
1243 return (fp
!= NULL
) ? 0 : 2;
1249 static void InitConfig()
1251 g_config
= new Config();
1252 g_config
->setTopLevelTag(_T("config"));
1254 // Set default data directory on Windows
1256 if (SHGetFolderPath(NULL
, CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, g_szDataDirectory
) == S_OK
)
1258 _tcscat(g_szDataDirectory
, _T("\\nxagentd"));
1264 * Initiate shutdown of connected external subagents
1266 static void InitiateExtSubagentShutdown()
1269 msg
.setCode(CMD_SHUTDOWN
);
1270 if (SendControlMessage(&msg
))
1271 _tprintf(_T("Control message sent successfully to master agent\n"));
1273 _tprintf(_T("ERROR: Unable to send control message to master agent\n"));
1281 static int GetUserId(char *name
)
1284 int id
= (int)strtol(name
, &eptr
, 10);
1289 struct passwd
*p
= getpwnam(name
);
1292 _tprintf(_T("Invalid user ID \"%hs\"\n"), name
);
1297 _tprintf(_T("Invalid user ID \"%hs\"\n"), name
);
1305 static int GetGroupId(char *name
)
1308 int id
= (int)strtol(name
, &eptr
, 10);
1313 struct group
*g
= getgrnam(name
);
1316 _tprintf(_T("Invalid group ID \"%hs\"\n"), name
);
1321 _tprintf(_T("Invalid group ID \"%hs\"\n"), name
);
1329 * Application entry point
1331 int main(int argc
, char *argv
[])
1333 int ch
, iExitCode
= 0, iAction
= ACTION_RUN_AGENT
;
1334 BOOL bRestart
= FALSE
;
1335 UINT32 dwOldPID
, dwMainPID
;
1338 TCHAR szModuleName
[MAX_PATH
];
1343 int uid
= 0, gid
= 0;
1346 InitNetXMSProcess();
1348 #if defined(__sun) || defined(_AIX) || defined(__hpux)
1349 signal(SIGPIPE
, SIG_IGN
);
1350 signal(SIGHUP
, SIG_IGN
);
1351 signal(SIGQUIT
, SIG_IGN
);
1352 signal(SIGUSR1
, SIG_IGN
);
1353 signal(SIGUSR2
, SIG_IGN
);
1356 // Check for alternate config file location
1358 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, _T("Software\\NetXMS\\Agent"), 0, KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
1360 dwSize
= MAX_PATH
* sizeof(TCHAR
);
1361 RegQueryValueEx(hKey
, _T("ConfigFile"), NULL
, NULL
, (BYTE
*)g_szConfigFile
, &dwSize
);
1362 dwSize
= MAX_PATH
* sizeof(TCHAR
);
1363 RegQueryValueEx(hKey
, _T("ConfigIncludeDir"), NULL
, NULL
, (BYTE
*)g_szConfigIncludeDir
, &dwSize
);
1367 pszEnv
= _tgetenv(_T("NXAGENTD_CONFIG"));
1369 nx_strncpy(g_szConfigFile
, pszEnv
, MAX_PATH
);
1371 pszEnv
= _tgetenv(_T("NXAGENTD_CONFIG_D"));
1373 nx_strncpy(g_szConfigIncludeDir
, pszEnv
, MAX_PATH
);
1376 // Parse command line
1378 iAction
= ACTION_HELP
;
1380 while((ch
= getopt(argc
, argv
, VALID_OPTIONS
)) != -1)
1384 case 'c': // Configuration file
1386 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szConfigFile
, MAX_PATH
);
1387 g_szConfigFile
[MAX_PATH
- 1] = 0;
1389 nx_strncpy(g_szConfigFile
, optarg
, MAX_PATH
);
1392 case 'C': // Configuration check only
1393 iAction
= ACTION_CHECK_CONFIG
;
1395 case 'd': // Run as daemon
1396 g_dwFlags
|= AF_DAEMON
;
1398 case 'D': // Turn on debug output
1399 s_debugLevel
= strtoul(optarg
, &eptr
, 0);
1400 if ((*eptr
!= 0) || (s_debugLevel
> 9))
1402 fprintf(stderr
, "Invalid debug level: %s\n", optarg
);
1407 case 'f': // Run in foreground
1408 g_dwFlags
&= ~AF_DAEMON
;
1411 case 'g': // set group ID
1412 gid
= GetGroupId(optarg
);
1415 case 'h': // Display help and exit
1416 iAction
= ACTION_HELP
;
1419 case 'H': // Hide window
1420 g_dwFlags
|= AF_HIDE_WINDOW
;
1423 case 'K': // Shutdown external sub-agents
1424 iAction
= ACTION_SHUTDOWN_EXT_AGENTS
;
1427 case 'p': // PID file
1429 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szPidFile
, MAX_PATH
);
1430 g_szPidFile
[MAX_PATH
- 1] = 0;
1432 nx_strncpy(g_szPidFile
, optarg
, MAX_PATH
);
1437 g_dwFlags
|= AF_CENTRAL_CONFIG
;
1439 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szConfigServer
, MAX_DB_STRING
);
1440 g_szConfigServer
[MAX_DB_STRING
- 1] = 0;
1442 nx_strncpy(g_szConfigServer
, optarg
, MAX_DB_STRING
);
1446 g_dwFlags
|= AF_REGISTER
;
1448 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szRegistrar
, MAX_DB_STRING
);
1449 g_szRegistrar
[MAX_DB_STRING
- 1] = 0;
1451 nx_strncpy(g_szRegistrar
, optarg
, MAX_DB_STRING
);
1454 case 'P': // Platform suffix
1456 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szPlatformSuffix
, MAX_PSUFFIX_LENGTH
);
1457 g_szPlatformSuffix
[MAX_PSUFFIX_LENGTH
- 1] = 0;
1459 nx_strncpy(g_szPlatformSuffix
, optarg
, MAX_PSUFFIX_LENGTH
);
1463 case 'u': // set user ID
1464 uid
= GetUserId(optarg
);
1467 case 'v': // Print version and exit
1468 _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"));
1469 iAction
= ACTION_NONE
;
1471 case 'W': // Watchdog process
1472 iAction
= ACTION_RUN_WATCHDOG
;
1473 dwMainPID
= strtoul(optarg
, NULL
, 10);
1475 case 'X': // Agent is being restarted
1477 dwOldPID
= strtoul(optarg
, NULL
, 10);
1479 case 'Z': // Create configuration file
1480 iAction
= ACTION_CREATE_CONFIG
;
1482 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szConfigFile
, MAX_PATH
);
1483 g_szConfigFile
[MAX_PATH
- 1] = 0;
1485 nx_strncpy(g_szConfigFile
, optarg
, MAX_PATH
);
1490 g_dwFlags
|= AF_INTERACTIVE_SERVICE
;
1492 case 'I': // Install Windows service
1493 iAction
= ACTION_INSTALL_SERVICE
;
1495 case 'R': // Remove Windows service
1496 iAction
= ACTION_REMOVE_SERVICE
;
1498 case 's': // Start Windows service
1499 iAction
= ACTION_START_SERVICE
;
1501 case 'S': // Stop Windows service
1502 iAction
= ACTION_STOP_SERVICE
;
1504 case 'E': // Install Windows event source
1505 iAction
= ACTION_INSTALL_EVENT_SOURCE
;
1507 case 'U': // Remove Windows event source
1508 iAction
= ACTION_REMOVE_EVENT_SOURCE
;
1510 case 'e': // Event source name
1512 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_windowsEventSourceName
, MAX_PATH
);
1513 g_windowsEventSourceName
[MAX_PATH
- 1] = 0;
1515 nx_strncpy(g_windowsEventSourceName
, optarg
, MAX_PATH
);
1518 case 'n': // Service name
1520 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_windowsServiceName
, MAX_PATH
);
1521 g_windowsServiceName
[MAX_PATH
- 1] = 0;
1523 nx_strncpy(g_windowsServiceName
, optarg
, MAX_PATH
);
1526 case 'N': // Service display name
1528 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_windowsServiceDisplayName
, MAX_PATH
);
1529 g_windowsServiceDisplayName
[MAX_PATH
- 1] = 0;
1531 nx_strncpy(g_windowsServiceDisplayName
, optarg
, MAX_PATH
);
1536 iAction
= ACTION_HELP
;
1544 #if !defined(_WIN32)
1547 if (setgid(gid
) != 0)
1548 _tprintf(_T("setgid(%d) call failed (%s)\n"), gid
, _tcserror(errno
));
1552 if (setuid(uid
) != 0)
1553 _tprintf(_T("setuid(%d) call failed (%s)\n"), uid
, _tcserror(errno
));
1556 if (!_tcscmp(g_szConfigFile
, _T("{search}")))
1558 TCHAR path
[MAX_PATH
] = _T("");
1559 const TCHAR
*homeDir
= _tgetenv(_T("NETXMS_HOME"));
1560 if (homeDir
!= NULL
)
1562 _sntprintf(path
, MAX_PATH
, _T("%s/etc/nxagentd.conf"), homeDir
);
1564 if ((path
[0] != 0) && (_taccess(path
, 4) == 0))
1566 _tcscpy(g_szConfigFile
, path
);
1568 else if (_taccess(PREFIX
_T("/etc/nxagentd.conf"), 4) == 0)
1570 _tcscpy(g_szConfigFile
, PREFIX
_T("/etc/nxagentd.conf"));
1572 else if (_taccess(_T("/Database/etc/nxagentd.conf"), 4) == 0) // for ZeroShell
1574 _tcscpy(g_szConfigFile
, _T("/Database/etc/nxagentd.conf"));
1576 else if (_taccess(_T("/usr/etc/nxagentd.conf"), 4) == 0)
1578 _tcscpy(g_szConfigFile
, _T("/usr/etc/nxagentd.conf"));
1582 _tcscpy(g_szConfigFile
, _T("/etc/nxagentd.conf"));
1585 if (!_tcscmp(g_szConfigIncludeDir
, _T("{search}")))
1587 TCHAR path
[MAX_PATH
] = _T("");
1588 const TCHAR
*homeDir
= _tgetenv(_T("NETXMS_HOME"));
1589 if (homeDir
!= NULL
)
1591 _sntprintf(path
, MAX_PATH
, _T("%s/etc/nxagentd.conf.d"), homeDir
);
1593 if ((path
[0] != 0) && (_taccess(path
, 4) == 0))
1595 _tcscpy(g_szConfigIncludeDir
, path
);
1597 else if (_taccess(PREFIX
_T("/etc/nxagentd.conf.d"), 4) == 0)
1599 _tcscpy(g_szConfigIncludeDir
, PREFIX
_T("/etc/nxagentd.conf.d"));
1601 else if (_taccess(_T("/Database/etc/nxagentd.conf.d"), 4) == 0)
1603 _tcscpy(g_szConfigIncludeDir
, _T("/Database/etc/nxagentd.conf.d"));
1605 else if (_taccess(_T("/usr/etc/nxagentd.conf.d"), 4) == 0)
1607 _tcscpy(g_szConfigIncludeDir
, _T("/usr/etc/nxagentd.conf.d"));
1611 _tcscpy(g_szConfigIncludeDir
, _T("/etc/nxagentd.conf.d"));
1615 if (!_tcscmp(g_szConfigFile
, _T("{search}")))
1617 TCHAR path
[MAX_PATH
];
1618 GetNetXMSDirectory(nxDirEtc
, path
);
1619 _tcscat(path
, _T("\\nxagentd.conf"));
1620 if (_taccess(path
, 4) == 0)
1622 _tcscpy(g_szConfigFile
, path
);
1626 _tcscpy(g_szConfigFile
, _T("C:\\nxagentd.conf"));
1629 if (!_tcscmp(g_szConfigIncludeDir
, _T("{search}")))
1631 TCHAR path
[MAX_PATH
];
1632 GetNetXMSDirectory(nxDirEtc
, path
);
1633 _tcscat(path
, _T("\\nxagentd.conf.d"));
1634 if (_taccess(path
, 4) == 0)
1636 _tcscpy(g_szConfigIncludeDir
, path
);
1640 _tcscpy(g_szConfigIncludeDir
, _T("C:\\nxagentd.conf.d"));
1646 DoRestartActions(dwOldPID
);
1650 // Do requested action
1653 case ACTION_RUN_AGENT
:
1654 // Set default value for session idle timeout based on
1655 // connect() timeout, if possible
1656 #if HAVE_SYSCTLBYNAME && !defined(_IPSO)
1661 nSize
= sizeof(nVal
);
1662 if (sysctlbyname("net.inet.tcp.keepinit", &nVal
, &nSize
, NULL
, 0) == 0)
1664 g_dwIdleTimeout
= nVal
/ 1000 + 15;
1669 if (g_dwFlags
& AF_CENTRAL_CONFIG
)
1671 if (s_debugLevel
> 0)
1672 _tprintf(_T("Downloading configuration from %s...\n"), g_szConfigServer
);
1673 if (DownloadConfig(g_szConfigServer
))
1675 if (s_debugLevel
> 0)
1676 _tprintf(_T("Configuration downloaded successfully\n"));
1680 if (s_debugLevel
> 0)
1681 _tprintf(_T("Configuration download failed\n"));
1685 if (g_config
->loadConfig(g_szConfigFile
, _T("agent")))
1687 const TCHAR
*dir
= g_config
->getValue(_T("/agent/ConfigIncludeDir"));
1689 nx_strncpy(g_szConfigIncludeDir
, dir
, MAX_PATH
);
1690 g_config
->loadConfigDirectory(g_szConfigIncludeDir
, _T("agent"));
1691 if (g_config
->parseTemplate(_T("agent"), m_cfgTemplate
))
1693 DecryptPassword(_T("netxms"), g_szSharedSecret
, g_szSharedSecret
, MAX_SECRET_LENGTH
);
1695 // try to guess executable path
1697 GetModuleFileName(GetModuleHandle(NULL
), s_executableName
, MAX_PATH
);
1700 char __buffer
[PATH_MAX
];
1702 #define __buffer s_executableName
1704 if (realpath(argv
[0], __buffer
) == NULL
)
1707 TCHAR
*path
= _tgetenv(_T("NETXMS_HOME"));
1710 nx_strncpy(s_executableName
, path
, sizeof(s_executableName
) / sizeof(s_executableName
[0]));
1714 nx_strncpy(s_executableName
, PREFIX
, sizeof(s_executableName
) / sizeof(s_executableName
[0]));
1716 _tcsncat(s_executableName
, _T("/bin/nxagentd"), sizeof(s_executableName
) / sizeof(s_executableName
[0]));
1721 int len
= strlen(__buffer
);
1722 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, __buffer
, len
, s_executableName
, len
);
1727 // Set exception handler
1729 if (g_dwFlags
& AF_CATCH_EXCEPTIONS
)
1730 SetExceptionHandler(SEHServiceExceptionHandler
, SEHServiceExceptionDataWriter
, s_dumpDir
,
1731 _T("nxagentd"), MSG_EXCEPTION
, g_dwFlags
& AF_WRITE_FULL_DUMP
, !(g_dwFlags
& AF_DAEMON
));
1734 if ((!_tcsicmp(g_szLogFile
, _T("{syslog}"))) ||
1735 (!_tcsicmp(g_szLogFile
, _T("{eventlog}"))))
1736 g_dwFlags
|= AF_USE_SYSLOG
;
1739 if (g_dwFlags
& AF_DAEMON
)
1751 ConsolePrintf(_T("Agent initialization failed\n"));
1757 if (g_dwFlags
& AF_DAEMON
)
1759 if (daemon(0, 0) == -1)
1761 perror("Unable to setup itself as a daemon");
1773 fp
= _tfopen(g_szPidFile
, _T("w"));
1776 _ftprintf(fp
, _T("%d"), s_pid
);
1784 ConsolePrintf(_T("Agent initialization failed\n"));
1792 if (s_shutdownCondition
!= INVALID_CONDITION_HANDLE
)
1793 ConditionDestroy(s_shutdownCondition
);
1796 LIBNETXMS_EXCEPTION_HANDLER
1801 ConsolePrintf(_T("Error parsing configuration file\n"));
1807 ConsolePrintf(_T("Error loading configuration file\n"));
1811 case ACTION_CHECK_CONFIG
:
1813 bool validConfig
= g_config
->loadConfig(g_szConfigFile
, _T("agent"), false);
1816 const TCHAR
*dir
= g_config
->getValue(_T("/agent/ConfigIncludeDir"));
1819 validConfig
= g_config
->loadConfigDirectory(dir
, _T("agent"), false);
1822 ConsolePrintf(_T("Error reading additional configuration files from \"%s\"\n"), dir
);
1829 g_config
->print(stdout
);
1830 validConfig
= g_config
->parseTemplate(_T("agent"), m_cfgTemplate
);
1835 ConsolePrintf(_T("Configuration file check failed\n"));
1840 case ACTION_RUN_WATCHDOG
:
1841 iExitCode
= WatchdogMain(dwMainPID
);
1843 case ACTION_CREATE_CONFIG
:
1844 iExitCode
= CreateConfig(CHECK_NULL_A(argv
[optind
]), CHECK_NULL_A(argv
[optind
+ 1]),
1845 CHECK_NULL_A(argv
[optind
+ 2]), CHECK_NULL_A(argv
[optind
+ 3]),
1846 argc
- optind
- 4, &argv
[optind
+ 4]);
1848 case ACTION_SHUTDOWN_EXT_AGENTS
:
1849 InitiateExtSubagentShutdown();
1853 case ACTION_INSTALL_SERVICE
:
1854 GetModuleFileName(GetModuleHandle(NULL
), szModuleName
, MAX_PATH
);
1855 InstallService(szModuleName
, g_szConfigFile
, s_debugLevel
);
1857 case ACTION_REMOVE_SERVICE
:
1860 case ACTION_INSTALL_EVENT_SOURCE
:
1861 GetModuleFileName(GetModuleHandle(NULL
), szModuleName
, MAX_PATH
);
1862 InstallEventSource(szModuleName
);
1864 case ACTION_REMOVE_EVENT_SOURCE
:
1865 RemoveEventSource();
1867 case ACTION_START_SERVICE
:
1868 StartAgentService();
1870 case ACTION_STOP_SERVICE
:
1875 _fputts(m_szHelpText
, stdout
);