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
);
83 void InitStaticSubagents();
87 extern TCHAR g_windowsServiceName
[];
88 extern TCHAR g_windowsServiceDisplayName
[];
91 void LIBNXAGENT_EXPORTABLE
InitSubAgentAPI(void (* writeLog
)(int, int, const TCHAR
*),
92 void (* sendTrap1
)(UINT32
, const TCHAR
*, const char *, va_list),
93 void (* sendTrap2
)(UINT32
, const TCHAR
*, int, TCHAR
**),
94 bool (* enumerateSessions
)(EnumerationCallbackResult (*)(AbstractCommSession
*, void *), void*),
95 AbstractCommSession
*(* findServerSession
)(UINT64
),
96 bool (* sendFile
)(void *, UINT32
, const TCHAR
*, long),
97 bool (* pushData
)(const TCHAR
*, const TCHAR
*, UINT32
, time_t),
98 void (* saveRegistry
)(), DB_HANDLE (* getLocalDatabaseHandle
)(),
99 CONDITION shutdownCondition
, Config
*registry
, const TCHAR
*dataDirectory
);
102 * Messages generated by mc.pl (for UNIX version only)
105 extern unsigned int g_dwNumMessages
;
106 extern const TCHAR
*g_szMessages
[];
110 * Valid options for getopt()
113 #define VALID_OPTIONS "c:CdD:e:EfhHiIKM:n:N:P:r:RsSUvX:W:Z:"
115 #define VALID_OPTIONS "c:CdD:fg:hKM:p:P:r:u:vX:W:Z:"
121 #define ACTION_NONE 0
122 #define ACTION_RUN_AGENT 1
123 #define ACTION_INSTALL_SERVICE 2
124 #define ACTION_REMOVE_SERVICE 3
125 #define ACTION_START_SERVICE 4
126 #define ACTION_STOP_SERVICE 5
127 #define ACTION_CHECK_CONFIG 6
128 #define ACTION_INSTALL_EVENT_SOURCE 7
129 #define ACTION_REMOVE_EVENT_SOURCE 8
130 #define ACTION_CREATE_CONFIG 9
131 #define ACTION_HELP 10
132 #define ACTION_RUN_WATCHDOG 11
133 #define ACTION_SHUTDOWN_EXT_AGENTS 12
138 UINT32 g_dwFlags
= AF_ENABLE_ACTIONS
| AF_ENABLE_AUTOLOAD
;
139 TCHAR g_szLogFile
[MAX_PATH
] = AGENT_DEFAULT_LOG
;
140 TCHAR g_szSharedSecret
[MAX_SECRET_LENGTH
] = _T("admin");
141 TCHAR g_szConfigFile
[MAX_PATH
] = AGENT_DEFAULT_CONFIG
;
142 TCHAR g_szFileStore
[MAX_PATH
] = AGENT_DEFAULT_FILE_STORE
;
143 TCHAR g_szDataDirectory
[MAX_PATH
] = AGENT_DEFAULT_DATA_DIR
;
144 TCHAR g_szPlatformSuffix
[MAX_PSUFFIX_LENGTH
] = _T("");
145 TCHAR g_szConfigServer
[MAX_DB_STRING
] = _T("not_set");
146 TCHAR g_szRegistrar
[MAX_DB_STRING
] = _T("not_set");
147 TCHAR g_szListenAddress
[MAX_PATH
] = _T("*");
148 TCHAR g_szConfigIncludeDir
[MAX_PATH
] = AGENT_DEFAULT_CONFIG_D
;
149 TCHAR g_masterAgent
[MAX_PATH
] = _T("not_set");
150 TCHAR g_szSNMPTrapListenAddress
[MAX_PATH
] = _T("*");
151 UINT16 g_wListenPort
= AGENT_LISTEN_PORT
;
152 ObjectArray
<ServerInfo
> g_serverList(8, 8, true);
153 UINT32 g_dwServerCount
= 0;
154 UINT32 g_dwExecTimeout
= 2000; // External process execution timeout in milliseconds
155 UINT32 g_dwSNMPTimeout
= 1500;
156 time_t g_tmAgentStartTime
;
157 UINT32 g_dwStartupDelay
= 0;
158 UINT32 g_dwMaxSessions
= 32;
159 UINT32 g_dwSNMPTrapPort
= 162;
160 UINT32 g_debugLevel
= (UINT32
)NXCONFIG_UNINITIALIZED_VALUE
;
162 UINT16 g_sessionAgentPort
= 28180;
164 UINT16 g_sessionAgentPort
= 0;
166 Config
*g_config
= NULL
;
168 UINT32 g_dwIdleTimeout
= 60; // Session idle timeout
170 UINT32 g_dwIdleTimeout
= 120; // Session idle timeout
174 TCHAR g_szPidFile
[MAX_PATH
] = _T("/var/run/nxagentd.pid");
180 static TCHAR
*m_pszActionList
= NULL
;
181 static TCHAR
*m_pszShellActionList
= NULL
;
182 static TCHAR
*m_pszServerList
= NULL
;
183 static TCHAR
*m_pszControlServerList
= NULL
;
184 static TCHAR
*m_pszMasterServerList
= NULL
;
185 static TCHAR
*m_pszSubagentList
= NULL
;
186 static TCHAR
*m_pszExtParamList
= NULL
;
187 static TCHAR
*m_pszExtListsList
= NULL
;
188 static TCHAR
*m_pszShExtParamList
= NULL
;
189 static TCHAR
*m_pszParamProviderList
= NULL
;
190 static TCHAR
*m_pszExtSubagentList
= NULL
;
191 static TCHAR
*m_pszAppAgentList
= NULL
;
192 static UINT32 s_enabledCiphers
= 0xFFFF;
193 static THREAD s_sessionWatchdogThread
= INVALID_THREAD_HANDLE
;
194 static THREAD s_listenerThread
= INVALID_THREAD_HANDLE
;
195 static THREAD s_eventSenderThread
= INVALID_THREAD_HANDLE
;
196 static THREAD s_snmpTrapReceiverThread
= INVALID_THREAD_HANDLE
;
197 static THREAD s_snmpTrapSenderThread
= INVALID_THREAD_HANDLE
;
198 static THREAD s_masterAgentListenerThread
= INVALID_THREAD_HANDLE
;
199 static TCHAR s_processToWaitFor
[MAX_PATH
] = _T("");
200 static TCHAR s_dumpDir
[MAX_PATH
] = _T("C:\\");
201 static UINT32 s_maxLogSize
= 16384 * 1024;
202 static UINT32 s_logHistorySize
= 4;
203 static UINT32 s_logRotationMode
= NXLOG_ROTATION_BY_SIZE
;
204 static TCHAR s_dailyLogFileSuffix
[64] = _T("");
205 static Config
*s_registry
= NULL
;
206 static TCHAR s_executableName
[MAX_PATH
];
208 static CONDITION s_subAgentsStopCondition
= INVALID_CONDITION_HANDLE
;
210 static CONDITION s_shutdownCondition
= INVALID_CONDITION_HANDLE
;
218 * Configuration file template
220 static NX_CFG_TEMPLATE m_cfgTemplate
[] =
222 { _T("Action"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszActionList
, NULL
},
223 { _T("ActionShellExec"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszShellActionList
, NULL
},
224 { _T("AppAgent"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszAppAgentList
, NULL
},
225 { _T("BackgroundLogWriter"), CT_BOOLEAN
, 0, 0, AF_BACKGROUND_LOG_WRITER
, 0, &g_dwFlags
, NULL
},
226 { _T("ControlServers"), CT_STRING_LIST
, ',', 0, 0, 0, &m_pszControlServerList
, NULL
},
227 { _T("CreateCrashDumps"), CT_BOOLEAN
, 0, 0, AF_CATCH_EXCEPTIONS
, 0, &g_dwFlags
, NULL
},
228 { _T("DataDirectory"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szDataDirectory
, NULL
},
229 { _T("DailyLogFileSuffix"), CT_STRING
, 0, 0, 64, 0, s_dailyLogFileSuffix
, NULL
},
230 { _T("DebugLevel"), CT_LONG
, 0, 0, 0, 0, &g_debugLevel
, &g_debugLevel
},
231 { _T("DisableIPv4"), CT_BOOLEAN
, 0, 0, AF_DISABLE_IPV4
, 0, &g_dwFlags
, NULL
},
232 { _T("DisableIPv6"), CT_BOOLEAN
, 0, 0, AF_DISABLE_IPV6
, 0, &g_dwFlags
, NULL
},
233 { _T("DumpDirectory"), CT_STRING
, 0, 0, MAX_PATH
, 0, s_dumpDir
, NULL
},
234 { _T("EnableActions"), CT_BOOLEAN
, 0, 0, AF_ENABLE_ACTIONS
, 0, &g_dwFlags
, NULL
},
235 { _T("EnabledCiphers"), CT_LONG
, 0, 0, 0, 0, &s_enabledCiphers
, NULL
},
236 { _T("EnableControlConnector"), CT_BOOLEAN
, 0, 0, AF_ENABLE_CONTROL_CONNECTOR
, 0, &g_dwFlags
, NULL
},
237 { _T("EnableProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_PROXY
, 0, &g_dwFlags
, NULL
},
238 { _T("EnableSNMPProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_SNMP_PROXY
, 0, &g_dwFlags
, NULL
},
239 { _T("EnableSNMPTrapProxy"), CT_BOOLEAN
, 0, 0, AF_ENABLE_SNMP_TRAP_PROXY
, 0, &g_dwFlags
, NULL
},
240 { _T("EnableSubagentAutoload"), CT_BOOLEAN
, 0, 0, AF_ENABLE_AUTOLOAD
, 0, &g_dwFlags
, NULL
},
241 { _T("EnableWatchdog"), CT_BOOLEAN
, 0, 0, AF_ENABLE_WATCHDOG
, 0, &g_dwFlags
, NULL
},
242 { _T("EncryptedSharedSecret"), CT_STRING
, 0, 0, MAX_SECRET_LENGTH
, 0, g_szSharedSecret
, NULL
},
243 { _T("ExecTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dwExecTimeout
, NULL
},
244 { _T("ExternalMasterAgent"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_masterAgent
, NULL
},
245 { _T("ExternalParameter"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszExtParamList
, NULL
},
246 { _T("ExternalList"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszExtListsList
, NULL
},
247 { _T("ExternalParameterShellExec"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszShExtParamList
, NULL
},
248 { _T("ExternalParametersProvider"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszParamProviderList
, NULL
},
249 { _T("ExternalSubagent"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszExtSubagentList
, NULL
},
250 { _T("FileStore"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szFileStore
, NULL
},
251 { _T("FullCrashDumps"), CT_BOOLEAN
, 0, 0, AF_WRITE_FULL_DUMP
, 0, &g_dwFlags
, NULL
},
252 { _T("ListenAddress"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szListenAddress
, NULL
},
253 { _T("ListenPort"), CT_WORD
, 0, 0, 0, 0, &g_wListenPort
, NULL
},
254 { _T("LogFile"), CT_STRING
, 0, 0, MAX_PATH
, 0, g_szLogFile
, NULL
},
255 { _T("LogHistorySize"), CT_LONG
, 0, 0, 0, 0, &s_logHistorySize
, NULL
},
256 { _T("LogRotationMode"), CT_LONG
, 0, 0, 0, 0, &s_logRotationMode
, NULL
},
257 { _T("LogUnresolvedSymbols"), CT_BOOLEAN
, 0, 0, AF_LOG_UNRESOLVED_SYMBOLS
, 0, &g_dwFlags
, NULL
},
258 { _T("MasterServers"), CT_STRING_LIST
, ',', 0, 0, 0, &m_pszMasterServerList
, NULL
},
259 { _T("MaxLogSize"), CT_LONG
, 0, 0, 0, 0, &s_maxLogSize
, NULL
},
260 { _T("MaxSessions"), CT_LONG
, 0, 0, 0, 0, &g_dwMaxSessions
, NULL
},
261 { _T("PlatformSuffix"), CT_STRING
, 0, 0, MAX_PSUFFIX_LENGTH
, 0, g_szPlatformSuffix
, NULL
},
262 { _T("RequireAuthentication"), CT_BOOLEAN
, 0, 0, AF_REQUIRE_AUTH
, 0, &g_dwFlags
, NULL
},
263 { _T("RequireEncryption"), CT_BOOLEAN
, 0, 0, AF_REQUIRE_ENCRYPTION
, 0, &g_dwFlags
, NULL
},
264 { _T("Servers"), CT_STRING_LIST
, ',', 0, 0, 0, &m_pszServerList
, NULL
},
265 { _T("SessionIdleTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dwIdleTimeout
, NULL
},
266 { _T("SessionAgentPort"), CT_WORD
, 0, 0, 0, 0, &g_sessionAgentPort
, NULL
},
267 { _T("SharedSecret"), CT_STRING
, 0, 0, MAX_SECRET_LENGTH
, 0, g_szSharedSecret
, NULL
},
268 { _T("SNMPTimeout"), CT_LONG
, 0, 0, 0, 0, &g_dwSNMPTimeout
, NULL
},
269 { _T("SNMPTrapListenAddress"), CT_STRING
, 0, 0, 0, 0, &g_szSNMPTrapListenAddress
, NULL
},
270 { _T("SNMPTrapPort"), CT_LONG
, 0, 0, 0, 0, &g_dwSNMPTrapPort
, NULL
},
271 { _T("StartupDelay"), CT_LONG
, 0, 0, 0, 0, &g_dwStartupDelay
, NULL
},
272 { _T("SubAgent"), CT_STRING_LIST
, '\n', 0, 0, 0, &m_pszSubagentList
, NULL
},
273 { _T("TimeOut"), CT_IGNORE
, 0, 0, 0, 0, NULL
, NULL
},
274 { _T("WaitForProcess"), CT_STRING
, 0, 0, MAX_PATH
, 0, s_processToWaitFor
, NULL
},
275 { _T(""), CT_END_OF_LIST
, 0, 0, 0, 0, NULL
, NULL
}
281 static TCHAR m_szHelpText
[] =
282 _T("Usage: nxagentd [options]\n")
283 _T("Where valid options are:\n")
284 _T(" -c <file> : Use configuration file <file> (default ") AGENT_DEFAULT_CONFIG
_T(")\n")
285 _T(" -C : Load configuration file, dump resulting configuration, and exit\n")
286 _T(" -d : Run as daemon/service\n")
287 _T(" -D <level> : Set debug level (0..9)\n")
289 _T(" -e <name> : Windows event source name\n")
291 _T(" -f : Run in foreground\n")
293 _T(" -g <gid> : Chhange group ID to <gid> after start\n")
295 _T(" -h : Display help and exit\n")
297 _T(" -H : Hide agent's window when in standalone mode\n")
298 _T(" -i : Installed Windows service must be interactive\n")
299 _T(" -I : Install Windows service\n")
301 _T(" -K : Shutdown all connected external sub-agents\n")
302 _T(" -M <addr> : Download config from management server <addr>\n")
304 _T(" -n <name> : Service name\n")
305 _T(" -N <name> : Service display name\n")
308 _T(" -p : Path to pid file (default: /var/run/nxagentd.pid)\n")
310 _T(" -P <text> : Set platform suffix to <text>\n")
311 _T(" -r <addr> : Register agent on management server <addr>\n")
313 _T(" -R : Remove Windows service\n")
314 _T(" -s : Start Windows servive\n")
315 _T(" -S : Stop Windows service\n")
318 _T(" -u <uid> : Chhange user ID to <uid> after start\n")
320 _T(" -v : Display version and exit\n")
324 * Server info: constructor
326 ServerInfo::ServerInfo(const TCHAR
*name
, bool control
, bool master
)
329 m_name
= MBStringFromWideString(name
);
331 m_name
= strdup(name
);
334 char *p
= strchr(m_name
, '/');
339 m_address
= InetAddress::resolveHostName(m_name
);
340 if (m_address
.isValid())
342 int bits
= strtol(p
, NULL
, 10);
343 if ((bits
>= 0) && (bits
<= ((m_address
.getFamily() == AF_INET
) ? 32 : 128)))
344 m_address
.setMaskBits(bits
);
346 m_redoResolve
= false;
350 m_address
= InetAddress::resolveHostName(m_name
);
351 m_redoResolve
= true;
356 m_lastResolveTime
= time(NULL
);
357 m_mutex
= MutexCreate();
361 * Server info: destructor
363 ServerInfo::~ServerInfo()
366 MutexDestroy(m_mutex
);
370 * Server info: resolve hostname if needed
372 void ServerInfo::resolve()
374 time_t now
= time(NULL
);
375 time_t age
= now
- m_lastResolveTime
;
376 if ((age
>= 3600) || ((age
> 300) && !m_address
.isValid()))
378 m_address
= InetAddress::resolveHostName(m_name
);
379 m_lastResolveTime
= now
;
384 * Server info: match address
386 bool ServerInfo::match(const InetAddress
&addr
)
391 bool result
= m_address
.isValid() ? m_address
.contain(addr
) : false;
392 MutexUnlock(m_mutex
);
399 static void SaveRegistry()
401 TCHAR regPath
[MAX_PATH
];
402 nx_strncpy(regPath
, g_szDataDirectory
, MAX_PATH
- _tcslen(REGISTRY_FILE_NAME
) - 1);
403 if (regPath
[_tcslen(regPath
) - 1] != FS_PATH_SEPARATOR_CHAR
)
404 _tcscat(regPath
, FS_PATH_SEPARATOR
);
405 _tcscat(regPath
, REGISTRY_FILE_NAME
);
407 String xml
= s_registry
->createXml();
408 FILE *f
= _tfopen(regPath
, _T("w"));
412 char *utf8xml
= UTF8StringFromWideString((const WCHAR
*)xml
);
416 fputs((const char *)xml
, f
);
422 nxlog_write(MSG_REGISTRY_SAVE_FAILED
, NXLOG_ERROR
, "ss", regPath
, _tcserror(errno
));
429 * Get our own console window handle (an alternative to Microsoft's GetConsoleWindow)
431 static HWND
GetConsoleHWND()
436 cpid
= GetCurrentProcessId();
439 hWnd
= FindWindowEx(NULL
, NULL
, _T("ConsoleWindowClass"), NULL
);
443 GetWindowThreadProcessId(hWnd
, &wpid
);
452 * Get proc address and write log file
454 static FARPROC
GetProcAddressAndLog(HMODULE hModule
, LPCSTR procName
)
458 ptr
= GetProcAddress(hModule
, procName
);
459 if ((ptr
== NULL
) && (g_dwFlags
& AF_LOG_UNRESOLVED_SYMBOLS
))
460 nxlog_write(MSG_NO_FUNCTION
, EVENTLOG_WARNING_TYPE
, "s", procName
);
465 * Shutdown thread (created by H_RestartAgent)
467 static THREAD_RESULT THREAD_CALL
ShutdownThread(void *pArg
)
469 DebugPrintf(INVALID_INDEX
, 1, _T("Shutdown thread started"));
472 return THREAD_OK
; // Never reached
481 static LONG
H_RestartAgent(const TCHAR
*action
, StringList
*args
, const TCHAR
*data
, AbstractCommSession
*session
)
483 DebugPrintf(INVALID_INDEX
, 1, _T("H_RestartAgent() called"));
485 TCHAR szCmdLine
[4096], szPlatformSuffixOption
[MAX_PSUFFIX_LENGTH
+ 16];
487 if (g_szPlatformSuffix
[0] != 0)
489 _sntprintf(szPlatformSuffixOption
, MAX_PSUFFIX_LENGTH
+ 16, _T("-P \"%s\" "), g_szPlatformSuffix
);
493 szPlatformSuffixOption
[0] = 0;
497 _sntprintf(szCmdLine
, 4096, _T("\"%s\" -c \"%s\" -n \"%s\" -e \"%s\" %s%s%s%s%s-D %d %s-X %u"), s_executableName
,
498 g_szConfigFile
, g_windowsServiceName
, g_windowsEventSourceName
,
499 (g_dwFlags
& AF_DAEMON
) ? _T("-d ") : _T(""),
500 (g_dwFlags
& AF_HIDE_WINDOW
) ? _T("-H ") : _T(""),
501 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T("-M ") : _T(""),
502 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? g_szConfigServer
: _T(""),
503 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T(" ") : _T(""),
504 g_debugLevel
, szPlatformSuffixOption
,
505 (g_dwFlags
& AF_DAEMON
) ? 0 : GetCurrentProcessId());
506 DebugPrintf(INVALID_INDEX
, 1, _T("Restarting agent with command line '%s'"), szCmdLine
);
510 PROCESS_INFORMATION pi
;
512 // Fill in process startup info structure
513 memset(&si
, 0, sizeof(STARTUPINFO
));
514 si
.cb
= sizeof(STARTUPINFO
);
516 // Create new process
517 if (!CreateProcess(NULL
, szCmdLine
, NULL
, NULL
, FALSE
,
518 (g_dwFlags
& AF_DAEMON
) ? (CREATE_NO_WINDOW
| DETACHED_PROCESS
) : (CREATE_NEW_CONSOLE
),
519 NULL
, NULL
, &si
, &pi
))
521 nxlog_write(MSG_CREATE_PROCESS_FAILED
, EVENTLOG_ERROR_TYPE
, "se", szCmdLine
, GetLastError());
522 dwResult
= ERR_EXEC_FAILED
;
527 CloseHandle(pi
.hThread
);
528 CloseHandle(pi
.hProcess
);
529 dwResult
= ERR_SUCCESS
;
531 if ((dwResult
== ERR_SUCCESS
) && (!(g_dwFlags
& AF_DAEMON
)))
533 if (g_dwFlags
& AF_HIDE_WINDOW
)
535 ConditionSet(s_shutdownCondition
);
539 ThreadCreate(ShutdownThread
, 0, NULL
);
544 _sntprintf(szCmdLine
, 4096, _T("\"%s\" -c \"%s\" %s%s%s%s-D %d %s-X %lu"), s_executableName
,
545 g_szConfigFile
, (g_dwFlags
& AF_DAEMON
) ? _T("-d ") : _T(""),
546 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T("-M ") : _T(""),
547 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? g_szConfigServer
: _T(""),
548 (g_dwFlags
& AF_CENTRAL_CONFIG
) ? _T(" ") : _T(""),
549 (int)g_debugLevel
, szPlatformSuffixOption
,
550 (unsigned long)s_pid
);
551 DebugPrintf(INVALID_INDEX
, 1, _T("Restarting agent with command line '%s'"), szCmdLine
);
552 return ExecuteCommand(szCmdLine
, NULL
, NULL
);
557 * This function writes message from subagent to agent's log
559 static void WriteSubAgentMsg(int logLevel
, int debugLevel
, const TCHAR
*pszMsg
)
561 if (logLevel
== EVENTLOG_DEBUG_TYPE
)
563 if (debugLevel
<= (int)g_debugLevel
)
564 nxlog_write(MSG_DEBUG
, EVENTLOG_DEBUG_TYPE
, "s", pszMsg
);
568 nxlog_write(MSG_SUBAGENT_MSG
, logLevel
, "s", pszMsg
);
573 * Signal handler for UNIX platforms
577 static THREAD_RESULT THREAD_CALL
SignalHandler(void *pArg
)
582 sigemptyset(&signals
);
583 sigaddset(&signals
, SIGTERM
);
584 sigaddset(&signals
, SIGINT
);
585 sigaddset(&signals
, SIGSEGV
);
586 sigaddset(&signals
, SIGHUP
);
587 sigaddset(&signals
, SIGUSR1
);
588 sigaddset(&signals
, SIGUSR2
);
589 #if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
590 sigaddset(&signals
, SIGPIPE
);
593 sigprocmask(SIG_BLOCK
, &signals
, NULL
);
597 if (sigwait(&signals
, &nSignal
) == 0)
618 sigprocmask(SIG_UNBLOCK
, &signals
, NULL
);
625 * Load platform subagent
627 static void LoadPlatformSubagent()
630 LoadSubAgent(_T("WINNT.NSM"));
632 #if HAVE_SYS_UTSNAME_H && !defined(_STATIC_AGENT)
634 TCHAR szName
[MAX_PATH
];
637 if (uname(&un
) != -1)
639 // Convert system name to lowercase
640 for(i
= 0; un
.sysname
[i
] != 0; i
++)
641 un
.sysname
[i
] = tolower(un
.sysname
[i
]);
642 if (!strcmp(un
.sysname
, "hp-ux"))
643 strcpy(un
.sysname
, "hpux");
644 _sntprintf(szName
, MAX_PATH
, _T("%hs.nsm"), un
.sysname
);
645 LoadSubAgent(szName
);
652 * Send file to server (subagent API)
654 static bool SendFileToServer(void *session
, UINT32 requestId
, const TCHAR
*file
, long offset
)
658 return ((CommSession
*)session
)->sendFile(requestId
, file
, offset
);
664 static void ParseServerList(TCHAR
*serverList
, bool isControl
, bool isMaster
)
668 for(pItem
= pEnd
= serverList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
670 pEnd
= _tcschr(pItem
, _T(','));
675 g_serverList
.add(new ServerInfo(pItem
, isControl
, isMaster
));
681 * Agent initialization
686 TCHAR regPath
[MAX_PATH
];
688 if (g_debugLevel
== (UINT32
)NXCONFIG_UNINITIALIZED_VALUE
)
691 if (!_tcscmp(g_szDataDirectory
, _T("{default}")))
693 GetNetXMSDirectory(nxDirData
, g_szDataDirectory
);
697 if (!(g_dwFlags
& AF_USE_SYSLOG
))
699 if (!nxlog_set_rotation_policy((int)s_logRotationMode
, (int)s_maxLogSize
, (int)s_logHistorySize
, s_dailyLogFileSuffix
))
700 if (!(g_dwFlags
& AF_DAEMON
))
701 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
703 if (!nxlog_open((g_dwFlags
& AF_USE_SYSLOG
) ? NXAGENTD_SYSLOG_NAME
: g_szLogFile
,
704 ((g_dwFlags
& AF_USE_SYSLOG
) ? NXLOG_USE_SYSLOG
: 0) |
705 ((g_dwFlags
& AF_BACKGROUND_LOG_WRITER
) ? NXLOG_BACKGROUND_WRITER
: 0) |
706 ((g_dwFlags
& AF_DAEMON
) ? 0 : NXLOG_PRINT_TO_STDOUT
),
711 g_dwNumMessages
, g_szMessages
))
714 _ftprintf(stderr
, _T("FATAL ERROR: Cannot open log file\n"));
717 nxlog_write(MSG_USE_CONFIG_D
, NXLOG_INFO
, "s", g_szConfigIncludeDir
);
718 nxlog_write(MSG_DEBUG_LEVEL
, NXLOG_INFO
, "d", g_debugLevel
);
720 ThreadPoolSetDebugCallback(DebugPrintfCallback
);
722 if (_tcscmp(g_masterAgent
, _T("not_set")))
724 g_dwFlags
|= AF_SUBAGENT_LOADER
;
725 DebugPrintf(INVALID_INDEX
, 1, _T("Switched to external subagent loader mode, master agent address is %s"), g_masterAgent
);
728 DebugPrintf(INVALID_INDEX
, 1, _T("Data directory: %s"), g_szDataDirectory
);
729 CreateFolder(g_szDataDirectory
);
731 // Initialize persistent storage
732 s_registry
= new Config
;
733 s_registry
->setTopLevelTag(_T("registry"));
734 nx_strncpy(regPath
, g_szDataDirectory
, MAX_PATH
- _tcslen(REGISTRY_FILE_NAME
) - 1);
735 if (regPath
[_tcslen(regPath
) - 1] != FS_PATH_SEPARATOR_CHAR
)
736 _tcscat(regPath
, FS_PATH_SEPARATOR
);
737 _tcscat(regPath
, REGISTRY_FILE_NAME
);
738 if (!s_registry
->loadXmlConfig(regPath
, "registry"))
740 nxlog_write(MSG_REGISTRY_LOAD_FAILED
, NXLOG_ERROR
, "s", regPath
);
744 CreateFolder(g_szFileStore
);
748 int wrc
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
751 nxlog_write(MSG_WSASTARTUP_FAILED
, NXLOG_ERROR
, "e", wrc
);
756 // Initialize API for subagents
757 s_subAgentsStopCondition
= ConditionCreate(TRUE
);
758 InitSubAgentAPI(WriteSubAgentMsg
, SendTrap
, SendTrap
, EnumerateSessions
, FindServerSession
,
759 SendFileToServer
, PushData
, SaveRegistry
, GetLocalDatabaseHandle
, s_subAgentsStopCondition
, s_registry
, g_szDataDirectory
);
760 DebugPrintf(INVALID_INDEX
, 1, _T("Subagent API initialized"));
762 // Initialize cryptografy
763 if (!InitCryptoLib(s_enabledCiphers
, DebugPrintfCallback
))
765 nxlog_write(MSG_INIT_CRYPTO_FAILED
, EVENTLOG_ERROR_TYPE
, "e", WSAGetLastError());
769 // Initialize libssl - it is not used by core agent
770 // but may be needed by some subagents. Allowing first load of libssl by
771 // subagent via dlopen() may lead to undesired side effects
772 #ifdef _WITH_ENCRYPTION
774 SSL_load_error_strings();
777 DBSetDebugPrintCallback(DebugPrintfCallback
);
778 DBInit(MSG_DB_LIBRARY
, MSG_SQL_ERROR
);
780 if (!OpenLocalDatabase())
782 nxlog_write(MSG_LOCAL_DB_OPEN_FAILED
, NXLOG_ERROR
, NULL
);
785 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
))
787 if (g_dwFlags
& AF_ENABLE_SNMP_PROXY
)
789 g_snmpProxyThreadPool
= ThreadPoolCreate(2, 128, _T("SNMPPROXY"));
793 // Initialize built-in parameters
794 if (!InitParameterList())
797 // Parse server lists
798 if (m_pszMasterServerList
!= NULL
)
799 ParseServerList(m_pszMasterServerList
, true, true);
800 if (m_pszControlServerList
!= NULL
)
801 ParseServerList(m_pszControlServerList
, true, false);
802 if (m_pszServerList
!= NULL
)
803 ParseServerList(m_pszServerList
, false, false);
805 // Add built-in actions
806 AddAction(_T("Agent.Restart"), AGENT_ACTION_SUBAGENT
, NULL
, H_RestartAgent
, _T("CORE"), _T("Restart agent"));
808 // Load platform subagents
810 InitStaticSubagents();
812 if (g_dwFlags
& AF_ENABLE_AUTOLOAD
)
814 LoadPlatformSubagent();
818 // Wait for external process if requested
819 if (s_processToWaitFor
[0] != 0)
821 DebugPrintf(INVALID_INDEX
, 1, _T("Waiting for process %s"), s_processToWaitFor
);
822 if (!WaitForProcess(s_processToWaitFor
))
823 nxlog_write(MSG_WAITFORPROCESS_FAILED
, EVENTLOG_ERROR_TYPE
, "s", s_processToWaitFor
);
826 // Load other subagents
827 if (m_pszSubagentList
!= NULL
)
829 for(pItem
= pEnd
= m_pszSubagentList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
831 pEnd
= _tcschr(pItem
, _T('\n'));
837 free(m_pszSubagentList
);
841 if (m_pszActionList
!= NULL
)
843 for(pItem
= pEnd
= m_pszActionList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
845 pEnd
= _tcschr(pItem
, _T('\n'));
849 if (!AddActionFromConfig(pItem
, FALSE
))
850 nxlog_write(MSG_ADD_ACTION_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
852 free(m_pszActionList
);
854 if (m_pszShellActionList
!= NULL
)
856 for(pItem
= pEnd
= m_pszShellActionList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
858 pEnd
= _tcschr(pItem
, _T('\n'));
863 if (!AddActionFromConfig(pItem
, TRUE
))
864 nxlog_write(MSG_ADD_ACTION_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
866 free(m_pszShellActionList
);
869 // Parse external parameters list
870 if (m_pszExtParamList
!= NULL
)
872 for(pItem
= pEnd
= m_pszExtParamList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
874 pEnd
= _tcschr(pItem
, _T('\n'));
878 if (!AddExternalParameter(pItem
, FALSE
, FALSE
))
879 nxlog_write(MSG_ADD_EXT_PARAM_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
881 free(m_pszExtParamList
);
883 if (m_pszShExtParamList
!= NULL
)
885 for(pItem
= pEnd
= m_pszShExtParamList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
887 pEnd
= _tcschr(pItem
, _T('\n'));
891 if (!AddExternalParameter(pItem
, TRUE
, FALSE
))
892 nxlog_write(MSG_ADD_EXT_PARAM_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
894 free(m_pszShExtParamList
);
897 // Parse external lists
898 if (m_pszExtListsList
!= NULL
)
900 for(pItem
= pEnd
= m_pszExtListsList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
902 pEnd
= _tcschr(pItem
, _T('\n'));
906 if (!AddExternalParameter(pItem
, FALSE
, TRUE
))
907 nxlog_write(MSG_ADD_EXT_PARAM_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
909 free(m_pszExtListsList
);
912 // Parse external parameters providers list
913 if (m_pszParamProviderList
!= NULL
)
915 for(pItem
= pEnd
= m_pszParamProviderList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
917 pEnd
= _tcschr(pItem
, _T('\n'));
921 if (!AddParametersProvider(pItem
))
922 nxlog_write(MSG_ADD_PARAM_PROVIDER_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
924 free(m_pszParamProviderList
);
927 // Parse external subagents list
928 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
) && (m_pszExtSubagentList
!= NULL
))
930 for(pItem
= pEnd
= m_pszExtSubagentList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
932 pEnd
= _tcschr(pItem
, _T('\n'));
936 if (!AddExternalSubagent(pItem
))
937 nxlog_write(MSG_ADD_EXTERNAL_SUBAGENT_FAILED
, EVENTLOG_WARNING_TYPE
, "s", pItem
);
939 free(m_pszExtSubagentList
);
942 // Parse application agents list
943 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
) && (m_pszAppAgentList
!= NULL
))
945 for(pItem
= pEnd
= m_pszAppAgentList
; pEnd
!= NULL
&& *pItem
!= 0; pItem
= pEnd
+ 1)
947 pEnd
= _tcschr(pItem
, _T('\n'));
951 RegisterApplicationAgent(pItem
);
953 free(m_pszAppAgentList
);
958 // If StartupDelay is greater than zero, then wait
959 if (g_dwStartupDelay
> 0)
961 if (g_dwFlags
& AF_DAEMON
)
963 ThreadSleep(g_dwStartupDelay
);
969 _tprintf(_T("XXXXXX%*s]\rWAIT ["), g_dwStartupDelay
, _T(" "));
971 for(i
= 0; i
< g_dwStartupDelay
; i
++)
974 _puttc(_T('.'), stdout
);
981 StartParamProvidersPoller();
984 g_tmAgentStartTime
= time(NULL
);
986 s_eventSenderThread
= ThreadCreateEx(TrapSender
, 0, NULL
);
988 // Start trap proxy threads(recieve and send), if trap proxy is enabled
989 if(g_dwFlags
& AF_ENABLE_SNMP_TRAP_PROXY
)
991 s_snmpTrapSenderThread
= ThreadCreateEx(SNMPTrapSender
, 0, NULL
);
992 s_snmpTrapReceiverThread
= ThreadCreateEx(SNMPTrapReceiver
, 0, NULL
);
995 if (g_dwFlags
& AF_SUBAGENT_LOADER
)
997 s_masterAgentListenerThread
= ThreadCreateEx(MasterAgentListener
, 0, NULL
);
1001 // Start network listener and session watchdog
1002 StartLocalDataCollector();
1003 s_listenerThread
= ThreadCreateEx(ListenerThread
, 0, NULL
);
1004 s_sessionWatchdogThread
= ThreadCreateEx(SessionWatchdog
, 0, NULL
);
1005 StartPushConnector();
1006 StartStorageDiscoveryConnector();
1007 StartSessionAgentConnector();
1008 if (g_dwFlags
& AF_ENABLE_CONTROL_CONNECTOR
)
1010 StartControlConnector();
1013 if (g_dwFlags
& AF_REGISTER
)
1015 RegisterOnServer(g_szRegistrar
);
1020 s_shutdownCondition
= ConditionCreate(TRUE
);
1024 // Start watchdog process
1025 if (!(g_dwFlags
& AF_SUBAGENT_LOADER
))
1027 if (g_dwFlags
& AF_ENABLE_WATCHDOG
)
1031 // Delete file used for upgrade if exists
1032 Config
*registry
= AgentOpenRegistry();
1033 const TCHAR
* szFullPath
= registry
->getValue(_T("/upgrade/file"));
1034 if(szFullPath
!= NULL
)
1036 _tremove(szFullPath
);
1038 registry
->deleteEntry(_T("/upgrade/file"));
1039 AgentCloseRegistry(true);
1049 DebugPrintf(INVALID_INDEX
, 2, _T("Shutdown() called"));
1050 if (g_dwFlags
& AF_ENABLE_WATCHDOG
)
1053 g_dwFlags
|= AF_SHUTDOWN
;
1054 ConditionSet(s_subAgentsStopCondition
);
1056 if (g_dwFlags
& AF_SUBAGENT_LOADER
)
1058 // TODO: shall we inform master agent listener about shutdown?
1059 //ThreadJoin(s_masterAgentListenerThread);
1063 ShutdownLocalDataCollector();
1064 ShutdownTrapSender();
1065 ThreadJoin(s_sessionWatchdogThread
);
1066 ThreadJoin(s_listenerThread
);
1068 ThreadJoin(s_eventSenderThread
);
1069 if(g_dwFlags
& AF_ENABLE_SNMP_TRAP_PROXY
)
1071 ShutdownSNMPTrapSender();
1072 ThreadJoin(s_snmpTrapReceiverThread
);
1073 ThreadJoin(s_snmpTrapSenderThread
);
1076 DestroySessionList();
1077 MsgWaitQueue::shutdown();
1079 if (g_dwFlags
& AF_ENABLE_SNMP_PROXY
)
1081 ThreadPoolDestroy(g_snmpProxyThreadPool
);
1084 UnloadAllSubAgents();
1085 CloseLocalDatabase();
1086 nxlog_write(MSG_AGENT_STOPPED
, EVENTLOG_INFORMATION_TYPE
, NULL
);
1091 // Notify main thread about shutdown
1093 ConditionSet(s_shutdownCondition
);
1097 #if !defined(_WIN32)
1098 _tremove(g_szPidFile
);
1107 nxlog_write(MSG_AGENT_STARTED
, NXLOG_INFO
, NULL
);
1109 if (g_dwFlags
& AF_DAEMON
)
1112 ConditionWait(s_shutdownCondition
, INFINITE
);
1114 StartMainLoop(SignalHandler
, NULL
);
1120 if (g_dwFlags
& AF_HIDE_WINDOW
)
1124 hWnd
= GetConsoleHWND();
1126 ShowWindow(hWnd
, SW_HIDE
);
1127 ConditionWait(s_shutdownCondition
, INFINITE
);
1132 _tprintf(_T("Agent running. Press ESC to shutdown.\n"));
1138 _tprintf(_T("Agent shutting down...\n"));
1142 _tprintf(_T("Agent running. Press Ctrl+C to shutdown.\n"));
1143 StartMainLoop(SignalHandler
, NULL
);
1144 _tprintf(_T("\nStopping agent...\n"));
1150 * Do necessary actions on agent restart
1152 static void DoRestartActions(UINT32 dwOldPID
)
1159 WaitForService(SERVICE_STOPPED
);
1160 StartAgentService();
1167 hProcess
= OpenProcess(SYNCHRONIZE
| PROCESS_TERMINATE
, FALSE
, dwOldPID
);
1168 if (hProcess
!= NULL
)
1170 if (WaitForSingleObject(hProcess
, 60000) == WAIT_TIMEOUT
)
1172 TerminateProcess(hProcess
, 0);
1174 CloseHandle(hProcess
);
1180 kill(dwOldPID
, SIGTERM
);
1181 for(i
= 0; i
< 30; i
++)
1184 if (kill(dwOldPID
, SIGCONT
) == -1)
1188 // Kill previous instance of agent if it's still running
1190 kill(dwOldPID
, SIGKILL
);
1195 * Create configuration file
1197 static int CreateConfig(const char *pszServer
, const char *pszLogFile
, const char *pszFileStore
,
1198 const char *configIncludeDir
, int iNumSubAgents
, char **ppszSubAgentList
)
1204 if (_taccess(g_szConfigFile
, 0) == 0)
1205 return 0; // File already exist, we shouldn't overwrite it
1207 fp
= _tfopen(g_szConfigFile
, _T("w"));
1210 currTime
= time(NULL
);
1211 _ftprintf(fp
, _T("#\n# NetXMS agent configuration file\n# Created by agent installer at %s#\n\n"),
1212 _tctime(&currTime
));
1213 _ftprintf(fp
, _T("MasterServers = %hs\nConfigIncludeDir = %hs\nLogFile = %hs\nFileStore = %hs\n"),
1214 pszServer
, configIncludeDir
, pszLogFile
, pszFileStore
);
1215 for(i
= 0; i
< iNumSubAgents
; i
++)
1216 _ftprintf(fp
, _T("SubAgent = %hs\n"), ppszSubAgentList
[i
]);
1219 return (fp
!= NULL
) ? 0 : 2;
1225 static void InitConfig()
1227 g_config
= new Config();
1228 g_config
->setTopLevelTag(_T("config"));
1230 // Set default data directory on Windows
1232 if (SHGetFolderPath(NULL
, CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, g_szDataDirectory
) == S_OK
)
1234 _tcscat(g_szDataDirectory
, _T("\\nxagentd"));
1240 * Initiate shutdown of connected external subagents
1242 static void InitiateExtSubagentShutdown()
1245 msg
.setCode(CMD_SHUTDOWN
);
1246 if (SendControlMessage(&msg
))
1247 _tprintf(_T("Control message sent successfully to master agent\n"));
1249 _tprintf(_T("ERROR: Unable to send control message to master agent\n"));
1257 static int GetUserId(char *name
)
1260 int id
= (int)strtol(name
, &eptr
, 10);
1265 struct passwd
*p
= getpwnam(name
);
1268 _tprintf(_T("Invalid user ID \"%hs\"\n"), name
);
1273 _tprintf(_T("Invalid user ID \"%hs\"\n"), name
);
1281 static int GetGroupId(char *name
)
1284 int id
= (int)strtol(name
, &eptr
, 10);
1289 struct group
*g
= getgrnam(name
);
1292 _tprintf(_T("Invalid group ID \"%hs\"\n"), name
);
1297 _tprintf(_T("Invalid group ID \"%hs\"\n"), name
);
1305 * Application entry point
1307 int main(int argc
, char *argv
[])
1309 int ch
, iExitCode
= 0, iAction
= ACTION_RUN_AGENT
;
1310 BOOL bRestart
= FALSE
;
1311 UINT32 dwOldPID
, dwMainPID
;
1314 TCHAR szModuleName
[MAX_PATH
];
1319 int uid
= 0, gid
= 0;
1322 InitNetXMSProcess();
1324 #if defined(__sun) || defined(_AIX) || defined(__hpux)
1325 signal(SIGPIPE
, SIG_IGN
);
1326 signal(SIGHUP
, SIG_IGN
);
1327 signal(SIGQUIT
, SIG_IGN
);
1328 signal(SIGUSR1
, SIG_IGN
);
1329 signal(SIGUSR2
, SIG_IGN
);
1332 // Check for alternate config file location
1334 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, _T("Software\\NetXMS\\Agent"), 0, KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
1336 dwSize
= MAX_PATH
* sizeof(TCHAR
);
1337 RegQueryValueEx(hKey
, _T("ConfigFile"), NULL
, NULL
, (BYTE
*)g_szConfigFile
, &dwSize
);
1338 dwSize
= MAX_PATH
* sizeof(TCHAR
);
1339 RegQueryValueEx(hKey
, _T("ConfigIncludeDir"), NULL
, NULL
, (BYTE
*)g_szConfigIncludeDir
, &dwSize
);
1343 pszEnv
= _tgetenv(_T("NXAGENTD_CONFIG"));
1345 nx_strncpy(g_szConfigFile
, pszEnv
, MAX_PATH
);
1347 pszEnv
= _tgetenv(_T("NXAGENTD_CONFIG_D"));
1349 nx_strncpy(g_szConfigIncludeDir
, pszEnv
, MAX_PATH
);
1352 // Parse command line
1354 iAction
= ACTION_HELP
;
1356 while((ch
= getopt(argc
, argv
, VALID_OPTIONS
)) != -1)
1360 case 'c': // Configuration file
1362 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szConfigFile
, MAX_PATH
);
1363 g_szConfigFile
[MAX_PATH
- 1] = 0;
1365 nx_strncpy(g_szConfigFile
, optarg
, MAX_PATH
);
1368 case 'C': // Configuration check only
1369 iAction
= ACTION_CHECK_CONFIG
;
1371 case 'd': // Run as daemon
1372 g_dwFlags
|= AF_DAEMON
;
1374 case 'D': // Turn on debug output
1375 g_debugLevel
= strtoul(optarg
, &eptr
, 0);
1376 if ((*eptr
!= 0) || (g_debugLevel
> 9))
1378 fprintf(stderr
, "Invalid debug level: %s\n", optarg
);
1383 case 'f': // Run in foreground
1384 g_dwFlags
&= ~AF_DAEMON
;
1387 case 'g': // set group ID
1388 gid
= GetGroupId(optarg
);
1391 case 'h': // Display help and exit
1392 iAction
= ACTION_HELP
;
1395 case 'H': // Hide window
1396 g_dwFlags
|= AF_HIDE_WINDOW
;
1399 case 'K': // Shutdown external sub-agents
1400 iAction
= ACTION_SHUTDOWN_EXT_AGENTS
;
1403 case 'p': // PID file
1405 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szPidFile
, MAX_PATH
);
1406 g_szPidFile
[MAX_PATH
- 1] = 0;
1408 nx_strncpy(g_szPidFile
, optarg
, MAX_PATH
);
1413 g_dwFlags
|= AF_CENTRAL_CONFIG
;
1415 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szConfigServer
, MAX_DB_STRING
);
1416 g_szConfigServer
[MAX_DB_STRING
- 1] = 0;
1418 nx_strncpy(g_szConfigServer
, optarg
, MAX_DB_STRING
);
1422 g_dwFlags
|= AF_REGISTER
;
1424 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szRegistrar
, MAX_DB_STRING
);
1425 g_szRegistrar
[MAX_DB_STRING
- 1] = 0;
1427 nx_strncpy(g_szRegistrar
, optarg
, MAX_DB_STRING
);
1430 case 'P': // Platform suffix
1432 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szPlatformSuffix
, MAX_PSUFFIX_LENGTH
);
1433 g_szPlatformSuffix
[MAX_PSUFFIX_LENGTH
- 1] = 0;
1435 nx_strncpy(g_szPlatformSuffix
, optarg
, MAX_PSUFFIX_LENGTH
);
1439 case 'u': // set user ID
1440 uid
= GetUserId(optarg
);
1443 case 'v': // Print version and exit
1444 _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"));
1445 iAction
= ACTION_NONE
;
1447 case 'W': // Watchdog process
1448 iAction
= ACTION_RUN_WATCHDOG
;
1449 dwMainPID
= strtoul(optarg
, NULL
, 10);
1451 case 'X': // Agent is being restarted
1453 dwOldPID
= strtoul(optarg
, NULL
, 10);
1455 case 'Z': // Create configuration file
1456 iAction
= ACTION_CREATE_CONFIG
;
1458 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_szConfigFile
, MAX_PATH
);
1459 g_szConfigFile
[MAX_PATH
- 1] = 0;
1461 nx_strncpy(g_szConfigFile
, optarg
, MAX_PATH
);
1466 g_dwFlags
|= AF_INTERACTIVE_SERVICE
;
1468 case 'I': // Install Windows service
1469 iAction
= ACTION_INSTALL_SERVICE
;
1471 case 'R': // Remove Windows service
1472 iAction
= ACTION_REMOVE_SERVICE
;
1474 case 's': // Start Windows service
1475 iAction
= ACTION_START_SERVICE
;
1477 case 'S': // Stop Windows service
1478 iAction
= ACTION_STOP_SERVICE
;
1480 case 'E': // Install Windows event source
1481 iAction
= ACTION_INSTALL_EVENT_SOURCE
;
1483 case 'U': // Remove Windows event source
1484 iAction
= ACTION_REMOVE_EVENT_SOURCE
;
1486 case 'e': // Event source name
1488 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_windowsEventSourceName
, MAX_PATH
);
1489 g_windowsEventSourceName
[MAX_PATH
- 1] = 0;
1491 nx_strncpy(g_windowsEventSourceName
, optarg
, MAX_PATH
);
1494 case 'n': // Service name
1496 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_windowsServiceName
, MAX_PATH
);
1497 g_windowsServiceName
[MAX_PATH
- 1] = 0;
1499 nx_strncpy(g_windowsServiceName
, optarg
, MAX_PATH
);
1502 case 'N': // Service display name
1504 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, optarg
, -1, g_windowsServiceDisplayName
, MAX_PATH
);
1505 g_windowsServiceDisplayName
[MAX_PATH
- 1] = 0;
1507 nx_strncpy(g_windowsServiceDisplayName
, optarg
, MAX_PATH
);
1512 iAction
= ACTION_HELP
;
1520 #if !defined(_WIN32)
1523 if (setgid(gid
) != 0)
1524 _tprintf(_T("setgid(%d) call failed (%s)\n"), gid
, _tcserror(errno
));
1528 if (setuid(uid
) != 0)
1529 _tprintf(_T("setuid(%d) call failed (%s)\n"), uid
, _tcserror(errno
));
1532 if (!_tcscmp(g_szConfigFile
, _T("{search}")))
1534 TCHAR path
[MAX_PATH
] = _T("");
1535 const TCHAR
*homeDir
= _tgetenv(_T("NETXMS_HOME"));
1536 if (homeDir
!= NULL
)
1538 _sntprintf(path
, MAX_PATH
, _T("%s/etc/nxagentd.conf"), homeDir
);
1540 if ((path
[0] != 0) && (_taccess(path
, 4) == 0))
1542 _tcscpy(g_szConfigFile
, path
);
1544 else if (_taccess(PREFIX
_T("/etc/nxagentd.conf"), 4) == 0)
1546 _tcscpy(g_szConfigFile
, PREFIX
_T("/etc/nxagentd.conf"));
1548 else if (_taccess(_T("/Database/etc/nxagentd.conf"), 4) == 0) // for ZeroShell
1550 _tcscpy(g_szConfigFile
, _T("/Database/etc/nxagentd.conf"));
1552 else if (_taccess(_T("/usr/etc/nxagentd.conf"), 4) == 0)
1554 _tcscpy(g_szConfigFile
, _T("/usr/etc/nxagentd.conf"));
1558 _tcscpy(g_szConfigFile
, _T("/etc/nxagentd.conf"));
1561 if (!_tcscmp(g_szConfigIncludeDir
, _T("{search}")))
1563 TCHAR path
[MAX_PATH
] = _T("");
1564 const TCHAR
*homeDir
= _tgetenv(_T("NETXMS_HOME"));
1565 if (homeDir
!= NULL
)
1567 _sntprintf(path
, MAX_PATH
, _T("%s/etc/nxagentd.conf.d"), homeDir
);
1569 if ((path
[0] != 0) && (_taccess(path
, 4) == 0))
1571 _tcscpy(g_szConfigIncludeDir
, path
);
1573 else if (_taccess(PREFIX
_T("/etc/nxagentd.conf.d"), 4) == 0)
1575 _tcscpy(g_szConfigIncludeDir
, PREFIX
_T("/etc/nxagentd.conf.d"));
1577 else if (_taccess(_T("/Database/etc/nxagentd.conf.d"), 4) == 0)
1579 _tcscpy(g_szConfigIncludeDir
, _T("/Database/etc/nxagentd.conf.d"));
1581 else if (_taccess(_T("/usr/etc/nxagentd.conf.d"), 4) == 0)
1583 _tcscpy(g_szConfigIncludeDir
, _T("/usr/etc/nxagentd.conf.d"));
1587 _tcscpy(g_szConfigIncludeDir
, _T("/etc/nxagentd.conf.d"));
1591 if (!_tcscmp(g_szConfigFile
, _T("{search}")))
1593 TCHAR path
[MAX_PATH
];
1594 GetNetXMSDirectory(nxDirEtc
, path
);
1595 _tcscat(path
, _T("\\nxagentd.conf"));
1596 if (_taccess(path
, 4) == 0)
1598 _tcscpy(g_szConfigFile
, path
);
1602 _tcscpy(g_szConfigFile
, _T("C:\\nxagentd.conf"));
1605 if (!_tcscmp(g_szConfigIncludeDir
, _T("{search}")))
1607 TCHAR path
[MAX_PATH
];
1608 GetNetXMSDirectory(nxDirEtc
, path
);
1609 _tcscat(path
, _T("\\nxagentd.conf.d"));
1610 if (_taccess(path
, 4) == 0)
1612 _tcscpy(g_szConfigIncludeDir
, path
);
1616 _tcscpy(g_szConfigIncludeDir
, _T("C:\\nxagentd.conf.d"));
1622 DoRestartActions(dwOldPID
);
1626 // Do requested action
1629 case ACTION_RUN_AGENT
:
1630 // Set default value for session idle timeout based on
1631 // connect() timeout, if possible
1632 #if HAVE_SYSCTLBYNAME && !defined(_IPSO)
1637 nSize
= sizeof(nVal
);
1638 if (sysctlbyname("net.inet.tcp.keepinit", &nVal
, &nSize
, NULL
, 0) == 0)
1640 g_dwIdleTimeout
= nVal
/ 1000 + 15;
1645 if (g_dwFlags
& AF_CENTRAL_CONFIG
)
1647 if (g_debugLevel
> 0)
1648 _tprintf(_T("Downloading configuration from %s...\n"), g_szConfigServer
);
1649 if (DownloadConfig(g_szConfigServer
))
1651 if (g_debugLevel
> 0)
1652 _tprintf(_T("Configuration downloaded successfully\n"));
1656 if (g_debugLevel
> 0)
1657 _tprintf(_T("Configuration download failed\n"));
1661 if (g_config
->loadConfig(g_szConfigFile
, _T("agent")))
1663 const TCHAR
*dir
= g_config
->getValue(_T("/agent/ConfigIncludeDir"));
1665 nx_strncpy(g_szConfigIncludeDir
, dir
, MAX_PATH
);
1666 g_config
->loadConfigDirectory(g_szConfigIncludeDir
, _T("agent"));
1667 if (g_config
->parseTemplate(_T("agent"), m_cfgTemplate
))
1669 DecryptPassword(_T("netxms"), g_szSharedSecret
, g_szSharedSecret
, MAX_SECRET_LENGTH
);
1671 // try to guess executable path
1673 GetModuleFileName(GetModuleHandle(NULL
), s_executableName
, MAX_PATH
);
1676 char __buffer
[PATH_MAX
];
1678 #define __buffer s_executableName
1680 if (realpath(argv
[0], __buffer
) == NULL
)
1683 TCHAR
*path
= _tgetenv(_T("NETXMS_HOME"));
1686 nx_strncpy(s_executableName
, path
, sizeof(s_executableName
) / sizeof(s_executableName
[0]));
1690 nx_strncpy(s_executableName
, PREFIX
, sizeof(s_executableName
) / sizeof(s_executableName
[0]));
1692 _tcsncat(s_executableName
, _T("/bin/nxagentd"), sizeof(s_executableName
) / sizeof(s_executableName
[0]));
1697 int len
= strlen(__buffer
);
1698 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, __buffer
, len
, s_executableName
, len
);
1703 // Set exception handler
1705 if (g_dwFlags
& AF_CATCH_EXCEPTIONS
)
1706 SetExceptionHandler(SEHServiceExceptionHandler
, SEHServiceExceptionDataWriter
, s_dumpDir
,
1707 _T("nxagentd"), MSG_EXCEPTION
, g_dwFlags
& AF_WRITE_FULL_DUMP
, !(g_dwFlags
& AF_DAEMON
));
1710 if ((!_tcsicmp(g_szLogFile
, _T("{syslog}"))) ||
1711 (!_tcsicmp(g_szLogFile
, _T("{eventlog}"))))
1712 g_dwFlags
|= AF_USE_SYSLOG
;
1715 if (g_dwFlags
& AF_DAEMON
)
1727 ConsolePrintf(_T("Agent initialization failed\n"));
1733 if (g_dwFlags
& AF_DAEMON
)
1735 if (daemon(0, 0) == -1)
1737 perror("Unable to setup itself as a daemon");
1749 fp
= _tfopen(g_szPidFile
, _T("w"));
1752 _ftprintf(fp
, _T("%d"), s_pid
);
1760 ConsolePrintf(_T("Agent initialization failed\n"));
1768 if (s_shutdownCondition
!= INVALID_CONDITION_HANDLE
)
1769 ConditionDestroy(s_shutdownCondition
);
1772 LIBNETXMS_EXCEPTION_HANDLER
1777 ConsolePrintf(_T("Error parsing configuration file\n"));
1783 ConsolePrintf(_T("Error loading configuration file\n"));
1787 case ACTION_CHECK_CONFIG
:
1789 bool validConfig
= g_config
->loadConfig(g_szConfigFile
, _T("agent"), false);
1792 const TCHAR
*dir
= g_config
->getValue(_T("/agent/ConfigIncludeDir"));
1795 validConfig
= g_config
->loadConfigDirectory(dir
, _T("agent"), false);
1798 ConsolePrintf(_T("Error reading additional configuration files from \"%s\"\n"), dir
);
1805 g_config
->print(stdout
);
1806 validConfig
= g_config
->parseTemplate(_T("agent"), m_cfgTemplate
);
1811 ConsolePrintf(_T("Configuration file check failed\n"));
1816 case ACTION_RUN_WATCHDOG
:
1817 iExitCode
= WatchdogMain(dwMainPID
);
1819 case ACTION_CREATE_CONFIG
:
1820 iExitCode
= CreateConfig(CHECK_NULL_A(argv
[optind
]), CHECK_NULL_A(argv
[optind
+ 1]),
1821 CHECK_NULL_A(argv
[optind
+ 2]), CHECK_NULL_A(argv
[optind
+ 3]),
1822 argc
- optind
- 4, &argv
[optind
+ 4]);
1824 case ACTION_SHUTDOWN_EXT_AGENTS
:
1825 InitiateExtSubagentShutdown();
1829 case ACTION_INSTALL_SERVICE
:
1830 GetModuleFileName(GetModuleHandle(NULL
), szModuleName
, MAX_PATH
);
1831 InstallService(szModuleName
, g_szConfigFile
);
1833 case ACTION_REMOVE_SERVICE
:
1836 case ACTION_INSTALL_EVENT_SOURCE
:
1837 GetModuleFileName(GetModuleHandle(NULL
), szModuleName
, MAX_PATH
);
1838 InstallEventSource(szModuleName
);
1840 case ACTION_REMOVE_EVENT_SOURCE
:
1841 RemoveEventSource();
1843 case ACTION_START_SERVICE
:
1844 StartAgentService();
1846 case ACTION_STOP_SERVICE
:
1851 _fputts(m_szHelpText
, stdout
);